In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
In [5]:
n_sims = 5000
n_years = 30
volatility_increase = 0.02

cov_slopes_5 = []
cov_slopes_10 = []
mad_slopes_5 = []
mad_slopes_10 = []
percentile_slopes = []

for sim in range(n_sims):
    base_sigma = 0.5
    sim_years = np.arange(n_years)
    
    losses = []
    for year in range(n_years):
        sigma_year = base_sigma * (1 + volatility_increase) ** year
        mu_year = 0
        loss = np.random.lognormal(mu_year, sigma_year)
        losses.append(loss)
    
    losses = pd.Series(losses)
    
    cov_5 = losses.rolling(window=5).std() / losses.rolling(window=5).mean()
    cov_10 = losses.rolling(window=10).std() / losses.rolling(window=10).mean()
    
    mad_5 = losses.rolling(window=5).apply(lambda x: np.mean(np.abs(x - x.mean())))
    mad_10 = losses.rolling(window=10).apply(lambda x: np.mean(np.abs(x - x.mean())))
    
    mean_losses = np.mean(losses)
    std_losses = np.std(losses)
    mu_fit = np.log(mean_losses**2 / np.sqrt(std_losses**2 + mean_losses**2))
    sigma_fit = np.sqrt(np.log(1 + (std_losses**2 / mean_losses**2)))
    pcts = stats.lognorm.cdf(losses, s=sigma_fit, scale=np.exp(mu_fit)) * 100
    pct_deviation = np.abs(pcts - 50)
    
    cov_slopes_5.append(np.polyfit(sim_years[~np.isnan(cov_5)], cov_5.dropna(), 1)[0])
    cov_slopes_10.append(np.polyfit(sim_years[~np.isnan(cov_10)], cov_10.dropna(), 1)[0])
    mad_slopes_5.append(np.polyfit(sim_years[~np.isnan(mad_5)], mad_5.dropna(), 1)[0])
    mad_slopes_10.append(np.polyfit(sim_years[~np.isnan(mad_10)], mad_10.dropna(), 1)[0])
    percentile_slopes.append(np.polyfit(sim_years, pct_deviation, 1)[0])

print(f"Mean CoV 5yr slope: {np.mean(cov_slopes_5):.6f}")
print(f"Mean CoV 10yr slope: {np.mean(cov_slopes_10):.6f}")
print(f"Mean MAD 5yr slope: {np.mean(mad_slopes_5):.6f}")
print(f"Mean MAD 10yr slope: {np.mean(mad_slopes_10):.6f}")
print(f"Mean Percentile deviation slope: {np.mean(percentile_slopes):.6f}")
Mean CoV 5yr slope: 0.010984
Mean CoV 10yr slope: 0.013413
Mean MAD 5yr slope: 0.017656
Mean MAD 10yr slope: 0.018748
Mean Percentile deviation slope: 0.304019

So we see that we set the volatility increase to be 2%, as measured by the sigma input to our logN. And then all our metrics do indeed track this increase on average.

In [7]:
# Part 2: How unusual is the absence of large years?
#df = pd.read_csv('SwissRe_CatLosses.csv')

weather_losses = df.iloc[:, 1]
eq_losses = df.iloc[:, 2]

years = df.iloc[:, 0]
values = df.iloc[:, 1]

total_losses = df.iloc[:, 1] + df.iloc[:, 2]

ln_total = np.log(total_losses)
slope_total = np.polyfit(years, ln_total, 1)[0]
inflation_rate = np.exp(slope_total) - 1

on_leveled = total_losses * (1 + inflation_rate) ** (len(total_losses) - 1 - np.arange(len(total_losses)))
In [11]:
threshold = 300  # $300m

# Count big years
big_years = on_leveled > threshold
n_big_years = big_years.sum()
n_total_years = len(on_leveled)
annual_prob = n_big_years / n_total_years

print(f"Years exceeding ${threshold}bn: {n_big_years} out of {n_total_years}")
print(f"Annual probability: {annual_prob:.1%}")

# Last 5 years
last_5_max = on_leveled.tail(5).max()
any_big_last_5 = (on_leveled.tail(5) > threshold).any()

print(f"\nLast 5 years max: ${last_5_max:,.0f}bn")
print(f"Any years above ${threshold}bn in last 5? {any_big_last_5}")

# Probability of no big years in 5-year window
p_no_big_year = (1 - annual_prob) ** 5
print(f"\nP(no year above ${threshold}bn in 5 years) = {p_no_big_year:.1%}")

# Simple visualization
plt.figure(figsize=(12, 6))
colors = ['red' if x > threshold else 'steelblue' for x in on_leveled]
plt.bar(years, on_leveled, color=colors, alpha=0.7)
plt.axhline(y=threshold, color='red', linestyle='--', alpha=0.5, label=f'${threshold}bn threshold')
plt.xlabel('Year')
plt.ylabel('On-Leveled Losses ($bn)')
plt.title('On-Leveled Global Natural Catastrophe Insured Losses')
plt.legend()
plt.tight_layout()
plt.show()
Years exceeding $300bn: 9 out of 55
Annual probability: 16.4%

Last 5 years max: $161bn
Any years above $300bn in last 5? False

P(no year above $300bn in 5 years) = 40.9%
No description has been provided for this image
In [ ]: