Tema 6: Métodos de simulación

Objetivos de aprendizaje

Después de completar este tema, debería poder:

  1. Explique la relación entre las distribuciones normal y lognormal y por qué se utiliza la distribución lognormal para modelar los precios de los activos cuando se utilizan rendimientos de activos compuestos continuamente
  2. Describa la simulación Monte Carlo y explique cómo se puede utilizar en aplicaciones de inversión
  3. Describa el uso del remuestreo bootstrap al realizar una simulación basada en datos observados en aplicaciones de inversión

Objetivo de aprendizaje 1: Distribuciones normales frente a lognormales

Concepto central: distribuciones estadísticas y modelado de activos

La relación entre las distribuciones normal y lognormal es fundamental para la modelización financiera, particularmente para comprender cómo se comportan de manera diferente los precios y los rendimientos de los activos. Este tema conecta las propiedades distributivas que estudiamos anteriormente con opciones prácticas de modelado. exam-focus

Propiedades de distribución normal

  • Simétrica: Curva en forma de campana con igual probabilidad en ambos lados de la media
  • Rango: Ilimitado (-∞ a +∞)
  • Aplicaciones: Modela los rendimientos de los activos, especialmente los rendimientos compuestos continuamente.
  • Parámetros: Media (μ) y desviación estándar (σ)

Propiedades de distribución lognormal

  • Asimétrica: distribución sesgada a la derecha
  • Rango: Limitado por debajo de cero (0 a +∞)
  • Aplicaciones: Modela precios de activos (que no pueden ser negativos)
  • Relación: Si X ~ N(μ, σ²), entonces e^X ~ Lognormal

¿Por qué Lognormal para los precios de los activos? exam-focus

Lógica Económica:

  1. No negatividad: los precios de los activos no pueden ser negativos
  2. Cambios porcentuales: los cambios de precios se modelan mejor como porcentajes que como cambios absolutos.
  3. Composición: la composición continua conduce naturalmente a distribuciones lognormales

Fundamentos Matemáticos: Si los rendimientos compuestos continuamente se distribuyen normalmente:

  • Sea rt = ln(S_t/S{t-1}) ~ N(μ, σ²)
  • Entonces St/S{t-1} = e^{r_t} ~ Lognormal
  • Por lo tanto, los precios siguen una distribución lognormal.

Fórmulas y cálculos

Transformación entre normal y lognormal

De devoluciones normales a precios lognormales:

If r_t ~ N(μ, σ²), then:
S_t = S_0 × e^{(μ - σ²/2)t + σ√t × Z}

Where:
- S_t = price at time t
- S_0 = initial price
- μ = expected return
- σ = volatility
- Z ~ N(0,1) = standard normal random variable
- t = time period

Parámetros de distribución lognormal:

If S ~ Lognormal(μ, σ²), then:
- E[S] = e^{μ + σ²/2}
- Var[S] = e^{2μ + σ²}(e^{σ²} - 1)
- Median[S] = e^μ

Relaciones clave:

ln(S_t) ~ N(ln(S_0) + (μ - σ²/2)t, σ²t)

Ejemplos prácticos

Ejemplo 1: Evolución del precio de las acciones

Dado:

  • Precio inicial de las acciones: $100
  • Rentabilidad anual esperada: 12%
  • Volatilidad anual: 20%
  • Horizonte temporal: 1 año

Cálculo:

S_1 = 100 × e^{(0.12 - 0.20²/2)×1 + 0.20×√1×Z}
S_1 = 100 × e^{0.10 + 0.20×Z}

Where Z is a standard normal random variable

Distribución de precios:

  • Precio medio: E[S_1] = 100 × e^{0,12 + 0,20²/2} = $112,75
  • La distribución está sesgada a la derecha con mediana < media

Ejemplo 2: Fundación de fijación de precios de opciones

El modelo de Black-Scholes supone:

S_T = S_0 × e^{(r - σ²/2)T + σ√T×Z}

This lognormal assumption enables:
- Analytical option pricing formulas
- Risk-neutral valuation
- Delta hedging strategies

Aplicación DeFi: modelado de precios de tokens

Simulaciones de pérdidas no permanentesLa simulación de las trayectorias de los precios de los tokens utilizando el modelo lognormal es la base para estimar las distribuciones de pérdidas no permanentes para Uniswap y otros proveedores de liquidez de AMM. Al analizar miles de trayectorias de precios, los LP pueden comprender toda la gama de resultados potenciales, no sólo el caso esperado. defi-application

Contexto: Los proveedores de liquidez en los creadores de mercado automatizados (AMM) enfrentan pérdidas impermanentes cuando los precios de los tokens divergen.

Configuración del modelo:

# Pseudo-code for impermanent loss simulation
def simulate_impermanent_loss(initial_price_A, initial_price_B, mu_A, mu_B, sigma_A, sigma_B, correlation, time_horizon, n_simulations):
 
    results = []
 
    for i in range(n_simulations):
        # Generate correlated normal returns
        Z1 = random.normal(0, 1)
        Z2 = correlation * Z1 + sqrt(1 - correlation²) * random.normal(0, 1)
 
        # Calculate lognormal price evolution
        price_A_final = initial_price_A * exp((mu_A - sigma_A²/2) * time_horizon + sigma_A * sqrt(time_horizon) * Z1)
        price_B_final = initial_price_B * exp((mu_B - sigma_B²/2) * time_horizon + sigma_B * sqrt(time_horizon) * Z2)
 
        # Calculate impermanent loss
        price_ratio_final = price_A_final / price_B_final
        price_ratio_initial = initial_price_A / initial_price_B
 
        il = 2 * sqrt(price_ratio_final / price_ratio_initial) / (1 + price_ratio_final / price_ratio_initial) - 1
 
        results.append(il)
 
    return results

Aplicación: Esta simulación ayuda a los LP a comprender las pérdidas potenciales en diferentes escenarios de mercado y supuestos de correlación.


Objetivo de aprendizaje 2: Simulación de Montecarlo

Concepto central: modelado probabilístico mediante simulación

La simulación Monte Carlo es una técnica computacional que utiliza muestreo aleatorio para resolver problemas que podrían ser deterministas en principio pero demasiado complejos para soluciones analíticas. Extiende el marco de probabilidad desde escenarios discretos hasta distribuciones continuas con miles de rutas.

Principios clave

1. Muestreo aleatorio: Genera variables aleatorias según distribuciones de probabilidad especificadas. 2. Repetición: Realice muchas iteraciones para generar confianza estadística 3. Agregación: Combina resultados para estimar la cantidad de interés 4. Convergencia: A medida que aumenta el número de simulaciones, las estimaciones convergen a los valores reales

Marco del proceso de Montecarlo

Paso 1: Definición del problema

  • Definir la cantidad a estimar (por ejemplo, valor de la opción, VaR de la cartera)
  • Identificar variables aleatorias clave y sus distribuciones.
  • Especificar la relación matemática entre entradas y salidas.

Paso 2: Especificación del modelo

  • Elija distribuciones de probabilidad apropiadas
  • Definir estructuras de correlación entre variables.
  • Establecer condiciones de contorno y restricciones.

Paso 3: Ejecución de la simulación

  • Generar muestras aleatorias a partir de distribuciones específicas.
  • Calcular el resultado de cada ruta de simulación.
  • Almacenar resultados para análisis estadístico.

Paso 4: Análisis de resultados

  • Calcular estadísticas resumidas (media, desviación estándar, percentiles)
  • Evaluar la convergencia y el error de simulación.
  • Realizar análisis de sensibilidad.

Fórmulas y cálculos

Estimador básico de Monte Carlo formula

θ̂_MC = (1/n) × Σ(i=1 to n) f(X_i)

Where:
- θ̂_MC = Monte Carlo estimate
- n = number of simulations
- f(X_i) = function value for simulation i
- X_i = random input vector for simulation i

Error estándar de la estimación de Monte Carlo formula

SE(θ̂_MC) = σ̂/√n

Where:
- σ̂ = sample standard deviation of f(X_i)
- n = number of simulations

Intervalos de confianza

95% CI: θ̂_MC ± 1.96 × SE(θ̂_MC)

Técnicas de reducción de varianza

Variaciones antitéticas:

For each random variable Z, also use -Z
This reduces variance when f is monotonic

El control varía:

Use known analytical results for similar problems
θ̂_CV = θ̂_MC + c(θ_control_MC - θ_control_true)

Ejemplos prácticos

Ejemplo 1: Valoración de opciones europeas

Configuración:

  • Precio de las acciones: $100
  • Precio de ejercicio: $105
  • Tasa libre de riesgo: 5%
  • Volatilidad: 20%
  • Tiempo hasta el vencimiento: 0,25 años

Proceso de simulación:

def monte_carlo_option_pricing(S0, K, r, sigma, T, n_simulations):
    payoffs = []
 
    for i in range(n_simulations):
        # Generate random stock price at expiration
        Z = random.normal(0, 1)
        ST = S0 * exp((r - 0.5 * sigma**2) * T + sigma * sqrt(T) * Z)
 
        # Calculate option payoff
        payoff = max(ST - K, 0)
        payoffs.append(payoff)
 
    # Discount to present value
    option_value = exp(-r * T) * mean(payoffs)
    standard_error = std(payoffs) / sqrt(n_simulations)
 
    return option_value, standard_error

Ejemplo 2: Valor en riesgo (VaR) de la cartera

Monte Carlo VaR amplía el marco matemáticas de cartera simulando la distribución completa de resultados en lugar de confiar en la aproximación normal.

VaR de cartera multiactivo:

def portfolio_var_simulation(weights, expected_returns, covariance_matrix, initial_value, confidence_level, time_horizon, n_simulations):
 
    portfolio_values = []
 
    for i in range(n_simulations):
        # Generate correlated asset returns
        random_returns = multivariate_normal(expected_returns * time_horizon, covariance_matrix * time_horizon)
 
        # Calculate portfolio return
        portfolio_return = sum(weights * random_returns)
 
        # Calculate portfolio value
        portfolio_value = initial_value * (1 + portfolio_return)
        portfolio_values.append(portfolio_value)
 
    # Calculate VaR
    portfolio_values.sort()
    var_index = int((1 - confidence_level) * n_simulations)
    var = initial_value - portfolio_values[var_index]
 
    return var

Ejemplo 3: Derivadas dependientes de la ruta

Precio de la opción asiática:

def asian_option_monte_carlo(S0, K, r, sigma, T, n_steps, n_simulations):
    dt = T / n_steps
    payoffs = []
 
    for i in range(n_simulations):
        path_sum = 0
        S = S0
 
        # Generate price path
        for j in range(n_steps):
            Z = random.normal(0, 1)
            S = S * exp((r - 0.5 * sigma**2) * dt + sigma * sqrt(dt) * Z)
            path_sum += S
 
        # Calculate average price
        average_price = path_sum / n_steps
 
        # Calculate payoff
        payoff = max(average_price - K, 0)
        payoffs.append(payoff)
 
    option_value = exp(-r * T) * mean(payoffs)
    return option_value
```### Aplicación DeFi: prueba de estrés de protocolo
 
#### Simulaciones de creadores de mercado automatizados (AMM)
 
**Dinámica del Fondo de Liquidez:**
 
```python
def simulate_amm_performance(initial_reserves_A, initial_reserves_B, fee_rate, price_process_params, trading_intensity, time_horizon, n_simulations):
 
    results = []
 
    for sim in range(n_simulations):
        reserves_A = initial_reserves_A
        reserves_B = initial_reserves_B
        total_fees = 0
 
        # Simulate price movements and trading
        for t in range(time_horizon):
            # Generate price movement
            price_change = generate_price_movement(price_process_params)
 
            # Simulate arbitrage trading
            if abs(price_change) > 0:
                trade_size = calculate_arbitrage_trade(reserves_A, reserves_B, price_change, trading_intensity)
 
                if trade_size > 0:
                    # Execute trade and collect fees
                    new_reserves_A, new_reserves_B, fee_collected = execute_trade(reserves_A, reserves_B, trade_size, fee_rate)
                    reserves_A, reserves_B = new_reserves_A, new_reserves_B
                    total_fees += fee_collected
 
        # Calculate final performance metrics
        impermanent_loss = calculate_impermanent_loss(initial_reserves_A, initial_reserves_B, reserves_A, reserves_B)
        net_return = total_fees - impermanent_loss
 
        results.append({
            'impermanent_loss': impermanent_loss,
            'fees_earned': total_fees,
            'net_return': net_return
        })
 
    return results

Previsión del precio del gas

def simulate_gas_prices(base_fee_params, priority_fee_params, network_congestion_model, time_steps, n_simulations):
 
    gas_price_paths = []
 
    for sim in range(n_simulations):
        base_fees = []
        priority_fees = []
 
        for t in range(time_steps):
            # Simulate network congestion
            congestion_level = generate_congestion(network_congestion_model, t)
 
            # Model base fee dynamics (EIP-1559)
            if t == 0:
                base_fee = base_fee_params['initial']
            else:
                utilization = congestion_level
                if utilization > 0.5:
                    base_fee = base_fees[-1] * (1 + base_fee_params['increase_factor'] * (utilization - 0.5) * 2)
                else:
                    base_fee = base_fees[-1] * (1 - base_fee_params['decrease_factor'] * (0.5 - utilization) * 2)
 
            # Model priority fee
            priority_fee = lognormal(priority_fee_params['mu'], priority_fee_params['sigma'])
 
            base_fees.append(base_fee)
            priority_fees.append(priority_fee)
 
        gas_price_paths.append({
            'base_fees': base_fees,
            'priority_fees': priority_fees,
            'total_fees': [b + p for b, p in zip(base_fees, priority_fees)]
        })
 
    return gas_price_paths

Objetivo de aprendizaje 3: remuestreo de Bootstrap

Concepto central: inferencia estadística no paramétrica

El remuestreo Bootstrap es un método estadístico no paramétrico que estima la distribución muestral de una estadística mediante un remuestreo con reemplazo de los datos originales. Se conecta con los conceptos de muestreo e inferencia que se tratan a continuación y es particularmente valioso cuando se desconocen las distribuciones teóricas o cuando los tamaños de muestra son pequeños.

Metodología Bootstrap

Principios clave:

  1. Distribución empírica: Utilice la muestra como una aproximación de la población.
  2. Remuestreo con reemplazo: Cree nuevas muestras extrayendo aleatoriamente de los datos originales.
  3. Inferencia estadística: Estimar intervalos de confianza y pruebas de hipótesis sin supuestos distributivos.
  4. Consistencia: Las estimaciones de Bootstrap convergen con los parámetros poblacionales reales a medida que aumenta el tamaño de la muestra.

Tipos de métodos Bootstrap

1. Bootstrap no paramétrico:

  • Remuestrear directamente a partir de los datos observados.
  • Sin supuestos distributivos
  • Más común en aplicaciones financieras.

2. Arranque paramétrico:

  • Ajustar un modelo paramétrico a los datos.
  • Remuestreo de la distribución montada.
  • Útil cuando se conoce la forma de distribución.

3. Bloqueo de arranque:

  • Preservar la estructura de series temporales.
  • Remuestrear bloques de observaciones consecutivas.
  • Esencial para datos financieros dependientes.

Fórmulas y cálculos

Algoritmo básico de arranque

1. Original sample: X = {x₁, x₂, ..., xₙ}
2. For b = 1 to B bootstrap replications:
   a. Draw random sample X*ᵦ = {x*₁, x*₂, ..., x*ₙ} with replacement from X
   b. Calculate statistic θ*ᵦ = f(X*ᵦ)
3. Bootstrap distribution: {θ*₁, θ*₂, ..., θ*ᵦ}

Error estándar de arranque

SE_bootstrap(θ̂) = √[(1/(B-1)) × Σ(θ*ᵦ - θ̄*)²]

Where:
- θ̄* = (1/B) × Σθ*ᵦ (bootstrap mean)
- B = number of bootstrap replications

Intervalos de confianza de Bootstrap

Método percentil:

95% CI: [θ*₍₀.₀₂₅₎, θ*₍₀.₉₇₅₎]
Where θ*₍ₚ₎ is the p-th percentile of bootstrap distribution

Sesgo corregido y acelerado (BCa):

Adjusted percentiles: [θ*₍α₁₎, θ*₍α₂₎]
Where α₁ and α₂ are bias and skewness adjusted

Bloquear Bootstrap para series temporales

Block length: l
Number of blocks: k = ⌈n/l⌉
Resample k blocks with replacement
Concatenate to form bootstrap sample

Ejemplos prácticos

Ejemplo 1: Intervalo de confianza del índice de Sharpe

Problema: Estimar el intervalo de confianza para el índice de Sharpe de la cartera utilizando datos históricos limitados.

def bootstrap_sharpe_ratio(returns, risk_free_rate, n_bootstrap=1000):
    n = len(returns)
    original_sharpe = (mean(returns) - risk_free_rate) / std(returns)
 
    bootstrap_sharpes = []
 
    for b in range(n_bootstrap):
        # Resample with replacement
        bootstrap_sample = [returns[random.randint(0, n-1)] for _ in range(n)]
 
        # Calculate bootstrap Sharpe ratio
        bootstrap_mean = mean(bootstrap_sample)
        bootstrap_std = std(bootstrap_sample)
        bootstrap_sharpe = (bootstrap_mean - risk_free_rate) / bootstrap_std
 
        bootstrap_sharpes.append(bootstrap_sharpe)
 
    # Calculate confidence interval
    bootstrap_sharpes.sort()
    ci_lower = bootstrap_sharpes[int(0.025 * n_bootstrap)]
    ci_upper = bootstrap_sharpes[int(0.975 * n_bootstrap)]
 
    return {
        'original_sharpe': original_sharpe,
        'ci_lower': ci_lower,
        'ci_upper': ci_upper,
        'standard_error': std(bootstrap_sharpes)
    }

Ejemplo 2: Validación del modelo VaR

Backtesting de modelos VaR:

def bootstrap_var_backtest(returns, var_estimates, confidence_level, n_bootstrap=1000):
    n = len(returns)
    violations = [1 if returns[i] < -var_estimates[i] else 0 for i in range(n)]
    actual_violation_rate = mean(violations)
    expected_violation_rate = 1 - confidence_level
 
    bootstrap_violation_rates = []
 
    for b in range(n_bootstrap):
        # Resample violation indicators
        bootstrap_violations = [violations[random.randint(0, n-1)] for _ in range(n)]
        bootstrap_rate = mean(bootstrap_violations)
        bootstrap_violation_rates.append(bootstrap_rate)
 
    # Test if actual rate is significantly different from expected
    p_value = sum([1 for rate in bootstrap_violation_rates if abs(rate - expected_violation_rate) >= abs(actual_violation_rate - expected_violation_rate)]) / n_bootstrap
 
    return {
        'actual_violation_rate': actual_violation_rate,
        'expected_violation_rate': expected_violation_rate,
        'p_value': p_value,
        'bootstrap_distribution': bootstrap_violation_rates
    }

Ejemplo 3: Simulación histórica vs VaR paramétrico

Comparación de métodos VaR:

def compare_var_methods(returns, confidence_level, n_bootstrap=1000):
    n = len(returns)
 
    # Historical Simulation VaR
    returns_sorted = sorted(returns)
    historical_var = -returns_sorted[int((1 - confidence_level) * n)]
 
    # Parametric VaR (normal assumption)
    mu = mean(returns)
    sigma = std(returns)
    parametric_var = -(mu + norm.ppf(1 - confidence_level) * sigma)
 
    # Bootstrap confidence intervals for Historical VaR
    bootstrap_historical_vars = []
 
    for b in range(n_bootstrap):
        bootstrap_sample = [returns[random.randint(0, n-1)] for _ in range(n)]
        bootstrap_sample.sort()
        bootstrap_var = -bootstrap_sample[int((1 - confidence_level) * n)]
        bootstrap_historical_vars.append(bootstrap_var)
 
    # Confidence interval for Historical VaR
    bootstrap_historical_vars.sort()
    hist_var_ci_lower = bootstrap_historical_vars[int(0.025 * n_bootstrap)]
    hist_var_ci_upper = bootstrap_historical_vars[int(0.975 * n_bootstrap)]
 
    return {
        'historical_var': historical_var,
        'parametric_var': parametric_var,
        'historical_var_ci': [hist_var_ci_lower, hist_var_ci_upper],
        'bootstrap_distribution': bootstrap_historical_vars
    }

Aplicación DeFi: MEV y análisis de liquidez

Análisis de oportunidades de valor máximo extraíble (MEV)

Problema: Analice la distribución de oportunidades MEV utilizando datos históricos limitados de transacciones de blockchain.

def bootstrap_mev_analysis(mev_opportunities, gas_costs, n_bootstrap=1000):
    """
    Analyze MEV opportunity distribution using bootstrap resampling
 
    mev_opportunities: list of observed MEV profits
    gas_costs: corresponding gas costs for each opportunity
    """
    n = len(mev_opportunities)
    net_profits = [mev - gas for mev, gas in zip(mev_opportunities, gas_costs)]
 
    # Original statistics
    original_mean_profit = mean(net_profits)
    original_profit_rate = sum([1 for profit in net_profits if profit > 0]) / n
    original_max_profit = max(net_profits)
 
    bootstrap_results = {
        'mean_profits': [],
        'profit_rates': [],
        'max_profits': [],
        'percentile_90': [],
        'sharpe_ratios': []
    }
 
    for b in range(n_bootstrap):
        # Resample MEV opportunities
        indices = [random.randint(0, n-1) for _ in range(n)]
        bootstrap_profits = [net_profits[i] for i in indices]
 
        # Calculate bootstrap statistics
        bootstrap_results['mean_profits'].append(mean(bootstrap_profits))
        bootstrap_results['profit_rates'].append(sum([1 for p in bootstrap_profits if p > 0]) / n)
        bootstrap_results['max_profits'].append(max(bootstrap_profits))
        bootstrap_results['percentile_90'].append(percentile(bootstrap_profits, 90))
 
        # MEV Sharpe ratio (profit/volatility)
        if std(bootstrap_profits) > 0:
            bootstrap_results['sharpe_ratios'].append(mean(bootstrap_profits) / std(bootstrap_profits))
 
    # Calculate confidence intervals
    confidence_intervals = {}
    for metric in bootstrap_results:
        sorted_values = sorted(bootstrap_results[metric])
        confidence_intervals[metric] = [
            sorted_values[int(0.025 * n_bootstrap)],
            sorted_values[int(0.975 * n_bootstrap)]
        ]
 
    return {
        'original_statistics': {
            'mean_profit': original_mean_profit,
            'profit_rate': original_profit_rate,
            'max_profit': original_max_profit
        },
        'bootstrap_distributions': bootstrap_results,
        'confidence_intervals': confidence_intervals
    }

Simulación de crisis de liquidez

Bloquear Bootstrap para eventos de liquidez correlacionados:

def bootstrap_liquidity_crisis(price_data, volume_data, liquidity_metrics, block_length=5, n_bootstrap=1000):
    """
    Use block bootstrap to preserve temporal dependencies in liquidity analysis
    """
    n = len(price_data)
    n_blocks = n // block_length
 
    crisis_indicators = []
 
    for b in range(n_bootstrap):
        # Block bootstrap to preserve time series structure
        bootstrap_indices = []
 
        for _ in range(n_blocks):
            start_idx = random.randint(0, n - block_length)
            block_indices = list(range(start_idx, start_idx + block_length))
            bootstrap_indices.extend(block_indices)
 
        # Trim to original length
        bootstrap_indices = bootstrap_indices[:n]
 
        # Create bootstrap time series
        bootstrap_prices = [price_data[i] for i in bootstrap_indices]
        bootstrap_volumes = [volume_data[i] for i in bootstrap_indices]
        bootstrap_liquidity = [liquidity_metrics[i] for i in bootstrap_indices]
 
        # Identify liquidity crisis periods
        crisis_periods = identify_liquidity_crisis(bootstrap_prices, bootstrap_volumes, bootstrap_liquidity)
 
        crisis_indicators.append({
            'crisis_frequency': len(crisis_periods) / n,
            'average_crisis_duration': mean([period['duration'] for period in crisis_periods]) if crisis_periods else 0,
            'max_price_impact': max([period['max_impact'] for period in crisis_periods]) if crisis_periods else 0
        })
 
    return crisis_indicators
 
def identify_liquidity_crisis(prices, volumes, liquidity_metrics, threshold_percentile=95):
    """
    Identify periods of liquidity crisis based on multiple indicators
    """
    # Calculate price volatility
    price_changes = [abs(prices[i] - prices[i-1]) / prices[i-1] for i in range(1, len(prices))]
 
    # Calculate liquidity stress indicators
    volume_threshold = percentile(volumes, 100 - threshold_percentile)  # Low volume
    liquidity_threshold = percentile(liquidity_metrics, threshold_percentile)  # High impact
    volatility_threshold = percentile(price_changes, threshold_percentile)  # High volatility
 
    crisis_periods = []
    in_crisis = False
    crisis_start = None
 
    for i in range(len(volumes)):
        # Crisis conditions: low volume AND (high liquidity impact OR high volatility)
        crisis_condition = (volumes[i] < volume_threshold and
                          (liquidity_metrics[i] > liquidity_threshold or
                           (i > 0 and price_changes[i-1] > volatility_threshold)))
 
        if crisis_condition and not in_crisis:
            # Start of crisis
            in_crisis = True
            crisis_start = i
        elif not crisis_condition and in_crisis:
            # End of crisis
            in_crisis = False
            crisis_periods.append({
                'start': crisis_start,
                'end': i,
                'duration': i - crisis_start,
                'max_impact': max(liquidity_metrics[crisis_start:i+1])
            })
 
    return crisis_periods

Integración y Aplicaciones Avanzadas

Combinando métodos de simulación

Enfoque híbrido Monte Carlo-Bootstrap

def hybrid_simulation_var(historical_returns, portfolio_weights, confidence_level, monte_carlo_steps=1000, bootstrap_replications=500):
    """
    Combine Monte Carlo simulation with bootstrap resampling for robust VaR estimation
    """
    var_estimates = []
 
    for b in range(bootstrap_replications):
        # Bootstrap resample historical returns
        n = len(historical_returns)
        bootstrap_returns = [historical_returns[random.randint(0, n-1)] for _ in range(n)]
 
        # Estimate parameters from bootstrap sample
        mu = mean(bootstrap_returns)
        sigma = std(bootstrap_returns)
 
        # Monte Carlo simulation with bootstrap-estimated parameters
        simulated_returns = []
        for mc in range(monte_carlo_steps):
            random_return = random.normal(mu, sigma)
            portfolio_return = sum([w * random_return for w in portfolio_weights])  # Simplified single-asset case
            simulated_returns.append(portfolio_return)
 
        # Calculate VaR from simulated returns
        simulated_returns.sort()
        var = -simulated_returns[int((1 - confidence_level) * monte_carlo_steps)]
        var_estimates.append(var)
 
    # Analyze distribution of VaR estimates
    final_var = mean(var_estimates)
    var_confidence_interval = [
        sorted(var_estimates)[int(0.025 * bootstrap_replications)],
        sorted(var_estimates)[int(0.975 * bootstrap_replications)]
    ]
 
    return {
        'var_estimate': final_var,
        'confidence_interval': var_confidence_interval,
        'var_distribution': var_estimates
    }

Validación de modelos y análisis de sensibilidad

Marco de comparación de métodos de simulación

def compare_simulation_methods(asset_returns, option_params, var_confidence_level):
    """
    Comprehensive comparison of different simulation approaches
    """
    results = {}
 
    # 1. Historical Simulation (Bootstrap-based)
    results['historical_simulation'] = bootstrap_historical_var(asset_returns, var_confidence_level)
 
    # 2. Parametric Monte Carlo
    mu = mean(asset_returns)
    sigma = std(asset_returns)
    results['parametric_monte_carlo'] = monte_carlo_var(mu, sigma, var_confidence_level)
 
    # 3. Bootstrap Monte Carlo Hybrid
    results['hybrid_method'] = hybrid_simulation_var(asset_returns, [1.0], var_confidence_level)
 
    # 4. Option Pricing Comparison
    if option_params:
        results['option_pricing'] = {
            'monte_carlo': monte_carlo_option_pricing(**option_params),
            'black_scholes': black_scholes_analytical(**option_params)
        }
 
    return results

Resumen y conclusiones clave

Relaciones críticas1. Conexión normal-lognormal: Rentabilidades continuamente compuestas (normal) → Precios de activos (lognormal)

  1. Jerarquía de simulación: simulación histórica ⊂ métodos Bootstrap ⊂ métodos Monte Carlo
  2. Aplicaciones DeFi: simulación financiera tradicional + factores específicos de Blockchain (gas, MEV, liquidez)

Mejores prácticas

  1. Validación del modelo: compare siempre los resultados de la simulación con las soluciones analíticas cuando estén disponibles
  2. Pruebas de convergencia: supervise la convergencia de la simulación y utilice tamaños de muestra adecuados
  3. Análisis de sensibilidad: Pruebe la solidez de diferentes supuestos de parámetros
  4. Dependencias de tiempo: utilice el arranque en bloque para datos de series de tiempo para preservar la estructura de correlación

Puntos de enfoque del examen exam-focus

  • Comprender POR QUÉ se utilizan distribuciones lognormales para los precios de activos
  • Conocer el proceso completo de simulación de Montecarlo
  • Distinguir entre métodos de arranque paramétricos y no paramétricos.
  • Aplicar métodos de simulación a problemas prácticos de inversión.
  • Reconocer cuándo cada método es el más apropiado

Consideraciones específicas de DeFi

  • Volatilidad del precio del gas: los modelos deben tener en cuenta la dinámica de congestión de la red
  • Extracción MEV: los métodos Bootstrap ayudan a analizar datos limitados de oportunidades MEV
  • Crisis de liquidez: el arranque en bloque preserva las dependencias temporales en los eventos de liquidez de DeFi
  • Pruebas de estrés de protocolo: las simulaciones de Monte Carlo evalúan la resiliencia del protocolo en escenarios extremos

Este enfoque integral de los métodos de simulación proporciona la base para un análisis cuantitativo avanzado tanto en las finanzas tradicionales como en las aplicaciones DeFi emergentes.