Download as pdf or txt
Download as pdf or txt
You are on page 1of 23

Risk Quantification

Monte Carlo Simulations and


Convolution in Python
Free Customizable Script

Prof. Hernan Huwyler, MBA CPA


Academic Director at IE Executive Education
Compliance, Risk Management, Controls, AI and Cyber
What will I get from this presentation?
1 Python script to model risk scenarios

Script for convolving distributions and generating 100k Monte Carlo simulations

2 No installations required

No need for paid risk software or MS Excel add-ons

3 Full control of variables

Customizable parameters and distributions to model your specific risk scenario

4 Immediate charts

Instant visualization of risk exposures through generated charts


Impact is modeled as a log-normal
distribution which better fit operational risks

Examples

• The typical cost of potential fines is


estimated to range from 1,000 to
2,000 USD per violation, which
includes 80% of the most frequent
breaches, based on historical data

• According to historical data, 80% of


interface malfunctions involve a range
of 100 to 200 corrupted records, with a
cost of 10 USD per record for
regeneration
How do I interpret the estimated losses?

8%
of the
potential 12%
losses of the potential losses
(best cases) 80% (worst cases, pessimistic estimation)
of the potential
losses
(most common)
Setting the loss variables in Python

Example

lower = 1000 # Lower value of the


potential loss
upper = 2000 # Upper value of the
potential loss
confidence_level = 0.8 # Confidence
level in the estimated loss
Probability is modeled as a Poisson
distribution for independent rare events

Examples

• According to historical data, the


average frequency of fines received is
estimated to be 4 during the 2-year
contracted work, following a Poisson
distribution
• The number of malfunction events in
interfaces has been observed to follow
a Poisson distribution with a rate of 4
events per year
Setting the probability variable in Python

Example

Events = 4 # Number of expected events


to materialize (Poisson distribution)
Combine 100,000 random simulations

Simulated Simulated Convolved


random losses random events exposures

=
Loss exceedance curve

Mean: 5878.21
75.0th Percentile Loss: 7727.16
P(10): 2021.54
P(20): 3016.65
P(30): 3804.37
P(40): 4547.16
P(50): 5317.37
7727 P(60): 6145.36
5878 P(70): 7142.74
P(80): 8405.11
P(90): 10396.85
P(99): 16494.88
How do I read the results?
A contingency reserve of 7,727 USD
should be established to mitigate potential
financial losses arising from the identified
risks, with the objective of covering 75%
of the most common occurrences

… or ….

To mitigate 75% of the most prevalent


cases of potential losses arising from the
assessed risk, a contingency reserve of
7,727 USD must be prudently allocated
Use instructions
Step 1 Open my GitHub repository
https://github.com/hwyler/HernanHuwylerRiskManagement/blob/main/PythonMinMaxConvMCS
¨
Step 2 Select and copy the code from line 22 to line 99
Use instructions
Step 3 Open the online Python compiler
https://cocalc.com/features/python

¨Step 4 Replace the line by the copied code and click Run
Use instructions
Step 5 Adjust the estimated number of risk events and financial losses for both the best-case
and worst-case scenarios for a given confidence level to better reflect your risk assessment
Use instructions
Step 6 Analyze the data and charts
Settings
Libraries
¨
• numpy: For numerical operations.
• matplotlib.pyplot: For plotting graphs
• scipy.stats: Specifically, importing lognorm, poisson, and norm for probability distributions

Data inputs

• Simulations: Number of scenarios to simulate


• Lower: Lower value of the potential loss
• Upper: Upper value of the potential loss
• Confidence_level: Confidence level in the estimated loss
• Events: Number of expected annual events to materialize (Poisson distribution)
• Reserve: This percentile is a measure of the risk exposure
• np.random.seed(123): Setting a random seed for replicability
Code flow
Calculations and charts

• Calculate lower and upper quantiles for the confidence level using the inverse cumulative
distribution function of the lognormal distribution
• Calculate the true mean and standard deviation of the log-transformed values for the
lognormal distribution
• Generate random values from a lognormal distribution to simulate impacts for losses
• Simulate Poisson-distributed random variables for the number of events
• Combine distributions using convolution for each scenario separately
• Calculate the total loss for each scenario
• Print the mean and given percentile of the simulated losses
• Calculate percentiles of the simulated losses and plot a loss exceedance curve
• Plot histograms for potential losses and potential incidents
Code
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import lognorm, poisson, norm

# Data input
Simulations = 1000000 # Number of scenarios to simulate
lower = 1000 # Lower value of the potential loss
upper = 2000 # Upper value of the potential loss
confidence_level = 0.8 # Confidence level in the estimated loss
Events = 4 # Number of expected annual events to materialize (Poisson distribution)
Reserve = 0.75 # This percentile is a measure of the risk exposure
np.random.seed(123) # Set a random seed for replicability

# Calculate lower and upper quantiles for the confidence level


error = (1 - confidence_level) / 2
lowerq = lognorm.ppf(error, s=np.log(upper / lower)) # Lower quantile for the confidence level
upperq = lognorm.ppf(1 - error, s=np.log(upper / lower)) # Upper quantile for the confidence level
# Calculate the true mean and standard deviation of the log-transformed values
true_mean_log = (np.log(lower) + np.log(upper)) / 2
true_sd_log = (np.log(upper) - np.log(lower)) / (2 * norm.ppf(0.9))

# Generate random values from a log-normal distribution to simulate impacts


Loss = lognorm.rvs(s=true_sd_log, scale=np.exp(true_mean_log), size=Simulations)

# Simulate Poisson-distributed random variables (number of events)


Prob = poisson.rvs(Events, size=Simulations)

# Combine distributions using convolution for each scenario separately


combined_distribution = [np.convolve(Prob[i], Loss[i], mode='full') for i in range(Simulations)]

# Calculate the total loss for each scenario


x = np.array([np.sum(combined_distribution[i]) for i in range(Simulations)])

# Display a summary of the simulated data


print(f'Mean: {np.mean(x)}')
# Calculate the percentiles and the given percentile of the simulated losses
loss_at_reserve = np.percentile(x, Reserve * 100)
print(f'{Reserve * 100}th Percentile Loss: {loss_at_reserve}')
percentiles = [10, 20, 30, 40, 50, 60, 70, 80, 90, 99]
for p in percentiles:
print(f'P({p}): {np.percentile(x, p)}')

# Graph a Loss Exceedance Curve


number_sequence = np.arange(0.01, 1.001, 0.001)
y = [np.percentile(x, i * 100) for i in number_sequence]
plt.plot(number_sequence, y, marker='o')
plt.xlabel('Percentile')
plt.ylabel('Loss')
plt.title('Loss Exceedance Curve')
plt.show()
# Plot histogram for potential losses
plt.figure(figsize=(8, 6))
plt.hist(Loss, bins=1000, density=True, alpha=0.8, color='skyblue', edgecolor='skyblue')
plt.title('Potential Losses', fontsize=16)
plt.xlabel('Loss', fontsize=14)
plt.ylabel('Density', fontsize=14)
plt.show()

# Plot histogram for potential incidents


plt.figure()
num_bins = int(np.max(Prob)) + 1 # Calculate the number of bins based on the maximum value in Prob
plt.hist(Prob, bins=num_bins, density=True)
plt.title('Potential Incidents')
plt.xlabel('Number of Incidents')
plt.ylabel('Density')
plt.show()
Prof. Hernan Huwyler

Academic Director IE Executive Education

Corporate Governance, AI, Compliance,


Quantitative Risk, Cybersecurity, and
Auditing

Zürich, Genève, Copenhagen, Madrid

You might also like