A Python package for actuarial risk modeling and simulation.
- Frequency-Severity Simulation: Monte Carlo modeling of aggregate losses using configurable frequency and severity distributions (Poisson, lognormal, gamma, Pareto, and more)
- Synthetic Claim Generation: Produce policy and claim level datasets for testing, benchmarking, and stress-testing actuarial workflows when real data is limited or restricted
- Distribution Fitting: Fit, compare, and diagnose candidate distributions against observed data with built-in goodness-of-fit testing
- Claim Development: Project claims through time using loss development factors, with native support for accident-year and development-age structures
- Risk Metrics: Compute mean, percentiles, VaR, TVaR, AEP, and OEP from simulated loss distributions
- Chainladder Integration: Convert simulated claims into triangle format for reserving, IBNR estimation, and ultimate loss projection using the
chainladderpackage - Reproducibility: Seed-controlled simulations and transparent validation tools designed to meet open-source and CAS review standards
- Python-Native: Built on ActStats, NumPy, pandas, and SciPy for seamless integration with the modern data science and actuarial analytics stack
pip install ActSimgit clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]fromActSimimportload_config, DistributionFitterfromactstatsimportactuarialasact# Load configurationconfig=load_config()
sev_data=act.lognormal(0.5,0.2).rvs(size=10000)
################################### Fit Severity ####################################### User specifies distributions and metrics distribution_names=config.distributions['severity']
metrics=config.metricssev_fitter=actfitter(sev_data, distributions=distribution_names, metrics=metrics)
sev_fitter.fit()
sev_fitter.best_fitssev_fitter.selected_fit- User Guide - Getting started and basic usage
- API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines
# Initialize fitter with config fileconfig=load_config()# ---------------------------------------------# Import required modules# ---------------------------------------------fromActSimimportload_config, DistributionFitterfromactstatsimportactuarialasact# ---------------------------------------------# 1. Generate Example Data# ---------------------------------------------# Severity data: Using lognormal distribution with mu=0.5 and sigma=0.2sev_data=act.lognormal(0.5, 0.2).rvs(size=10000)
# Frequency data: Using Poisson distribution with λ=10freq_data=act.poisson.rvs(10, 1000)
# ---------------------------------------------# 2. Load Configuration# ---------------------------------------------# This loads distribution lists and metrics from the ActSim config fileconfig=load_config()
# ---------------------------------------------# 3. Fit Severity Distributions# ---------------------------------------------# Get severity distributions and metrics from configdistribution_names=config.distributions['severity']
metrics=config.metrics# Initialize severity fittersev_fitter=DistributionFitter(sev_data, distributions=distribution_names, metrics=metrics)
# Perform fittingsev_fitter.fit()
# View best fits and selected distributionprint("Best fits:", sev_fitter.best_fits)
print("Selected fit:", sev_fitter.selected_fit)
print("Selected distribution object:", sev_fitter.get_selected_dist())
# Manually selecting a distribution (example: 'uniform')sev_fitter.select_distribution('uniform')
selected_fit=sev_fitter.selected_fit# Print details of the selected fitprint("Selected fitting distribution:", selected_fit['name'])
print("Parameters:", selected_fit['params'])
print("AIC:", selected_fit['aic'])
print("BIC:", selected_fit['bic'])
# Calculate statistics for severitysev_fitter.calculate_statistics()
# Plot predictionssev_fitter.plot_predictions()
# Print summary reportsev_fitter.summary()
# ---------------------------------------------# 4. Generate Samples from Severity Fit# ---------------------------------------------samples=sev_fitter.sample(size=10)
print("Generated samples:", samples)
# Generate mixed samples (e.g., weighted combinations)samples=sev_fitter.sample_mixed(0.1, 0.1, size=10)
print("Generated samples:", samples)
# ---------------------------------------------# 5. Fit Frequency Distributions# ---------------------------------------------distribution_names=config.distributions['frequency']
metrics=config.metrics# Initialize frequency fitterfreq_fitter=DistributionFitter(freq_data, distributions=distribution_names, metrics=metrics)
# Show available frequency distributionsprint("Frequency distributions:", freq_fitter.distributions)
# Perform fittingfreq_fitter.fit()
# View best fits and summaryprint("Frequency best fits:", freq_fitter.best_fits)
print("Frequency selected fit:", freq_fitter.selected_fit)
freq_fitter.summary()########################################### Stochastic Simulation ############################################## ---------------------------------------------# 1. Import Required Modules# ---------------------------------------------fromActSimimportStochasticSimulatorfromactstatsimportactuarialasact# ---------------------------------------------# 2. Define Frequency and Severity Distributions# ---------------------------------------------# Frequency distribution: Poisson with λ=10freq_dist='poisson'freq_params= (10,)
# Severity distribution: Lognormal with mu=10, sigma=0.5sev_dist='lognormal'sev_params= (10, 0.5)
# Preview quantile (e.g., 80th percentile of Poisson)quantile_80=act.poisson.ppf(0.8, 10)
print("80th percentile of Poisson(10):", quantile_80)
# ---------------------------------------------# 3. Initialize Simulator with Different Levels of Complexity# ---------------------------------------------# With copulasimulator=StochasticSimulator(freq_dist, freq_params, sev_dist, sev_params, 10000, True, 1234, 0.6, 'frank', 0.6)
# with linear correlationsimulator=StochasticSimulator(freq_dist, freq_params, sev_dist, sev_params, 10000, True, 1234, 0.6)
# Without copula or linear correlationsimulator=StochasticSimulator(freq_dist, freq_params, sev_dist, sev_params, 10000, True, 1234)
# ---------------------------------------------# 4. Generate Simulated Aggregate Losses# ---------------------------------------------simulations=simulator.gen_agg_simulations()
# Access full simulation DataFrameprint("All simulations preview:")
print(simulator.all_simulations.head())
# ---------------------------------------------# 5. Analyze Simulation Results# ---------------------------------------------# Calculate aggregate percentile (e.g., 99.2%)percentile_99_2=simulator.calc_agg_percentile(99.2)
print("99.2% Aggregate Loss Percentile:", percentile_99_2)
# Plot loss distribution histogramsimulator.plot_distribution()
# Show simulation meanprint("Mean simulated loss:", simulator.results.mean())
# If copula is used, plot frequency-severity correlation structuresimulator.plot_correlated_variables()
# Summary statistics and shape diagnosticssimulator.analyze_results()
# ---------------------------------------------# 6. Apply Deductibles and Limits# ---------------------------------------------# Apply per occurrence deductible of 1,000# Occurrence limit of 10,000# Annual aggregate deductible of 100,000# Annual aggregate limit of 300,000gross_loss=simulator.apply_deductible_and_limit(1000, 10000, 100000, 300000)
# Assign processed loss to expected structure for reportinggross_loss['amount'] =gross_loss['gross_loss']
# Re-analyze results based on capped/layered gross losssimulator.analyze_results(all_simulations=gross_loss)
# ---------------------------------------------# 7. Export Simulated Data to CSV# ---------------------------------------------simulator.all_simulationsSample correlation matrix csv file
Correlation Matrix,LoB1,LoB2,LoB3,LoB4,LoB5LoB1,1,0.5,0.5,0.3,0.2LoB2,0.5,1,0.5,0.7,0.3LoB3,0.5,0.5,1,0.2,0.5LoB4,0.3,0.7,0.2,1,0.3LoB5,0.2,0.3,0.5,0.3,1Sample multi-line distribution json file
[
{
"index": 1,
"dist_name": "LoB1",
"dist_type": "gamma",
"dist_param": [2, 1]
},
{
"index": 2,
"dist_name": "LoB2",
"dist_type": "lognormal",
"dist_param": [2, 1]
},
{
"index": 3,
"dist_name": "LoB3",
"dist_type": "gamma",
"dist_param": [3, 1]
},
{
"index": 4,
"dist_name": "LoB4",
"dist_type": "lognormal",
"dist_param": [3, 2]
},
{
"index": 5,
"dist_name": "LoB5",
"dist_type": "gamma",
"dist_param": [4, 2]
}
]importpandasaspdfromActSimimportStochasticSimulator##### Generate correlated mutivariate distributioncorr_matrix_file='examples/correlated_sim/corr_matrix.csv'dist_list_file='examples/correlated_sim/dist_list.json'simulator=StochasticSimulator("normal", [1,0], "normal",[1,0], 100000, True, 1234) # placeholder parameters for the simulatorsimulator.gen_multivariate_corr_simulations(corr_matrix_file, dist_list_file, True)
simulator._all_simulations_datadata=pd.DataFrame(simulator._all_simulations_data)
data_t=data.transpose()
# Compute correlation matrixcorrelation_matrix=data_t.corr()
print(correlation_matrix)################################################ Synthetic Claim Simulation ##################################################importpandasaspdimportnumpyasnpfromActSimimportClaimSimulator# Simulate policy characteristicspolicies=pd.DataFrame({
'policy_id': range(1, 101),
'freq_dist': 'poisson',
'freq_params': list(zip(np.random.uniform(0.6, 0.8, 100).round(2),)), 'sev_dist': 'lognormal',
'sev_params': list(zip(np.random.uniform(0.8, 1.2, 100).round(2), np.random.uniform(0.3, 0.7, 100).round(2))),
'start_date': pd.Timestamp('2023-01-01'),
'end_date': pd.Timestamp('2023-12-31'),
})
# Instantiate the ClaimSimulator with input policies and np random seed 42claim_sim=ClaimSimulator(policies, 42)
# Access the processed policy DataFrameclaim_sim.policies# Run the claim simulation (frequency × severity) for all policy groupsclaim_sim.simulate_claims()
# Access the resulting simulated claim recordsclaim_sim.claim_data# Set parameters for the non-homogeneous Poisson process (NHPP) for date simulationlambda0=10# Baseline intensityalpha=0.5# Seasonality amplitudephase=0# Phase shift of the seasonalityT=1# Duration of the exposure in years# Simulate claim occurrence dates using a seasonal NHPPclaim_sim.simulate_dates_nhpp(lambda0, alpha, phase, T)
# Define base loss development factors (LDFs) by development monthbase_LDFs= {
0: 2, # Initial LDF at 0 months3: 1.5, # LDF at 3 months6: 1.2,
9: 1.1,
12: 1.05,
15: 1.02,
18: 1.00# Ultimate LDF at 18 months
}
volatility=0.1# Standard deviation for stochastic fluctuation in LDFstail_factor=1.0# No additional tail development (fully developed at 18 months)# Simulate the claim development triangles based on LDFs and apply stochastic volatilityclaim_sim.simulate_claim_development(base_LDFs, volatility, tail_factor)
# Access the simulated claim development triangle or long-format development dataclaim_sim.claim_development# Access updated policies (could include mappings to simulated claims)claim_sim.policies# Save the simulated claim development data to a file (replace with actual path)claim_sim.save_claim_development('sample_file_path')# Clone the repository
git clone https://github.com/jzhng105/ActSim.git
cd ActSim
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activateWe welcome contributions! Please see our Contributing Guide for details.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
pytest) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the Apache License - see the LICENSE file for details.
If you use ActSim in your research, please cite:
@software{ActSim2025,
title={ActSim: A Python package for actuarial risk modeling and simulation},
author={Juntao Zhang},
year={2025},
url={https://github.com/casact/ActSim}
}- Documentation: docs/
- Issues: GitHub Issues
- Discussions: GitHub Discussions
See CHANGELOG.md for a list of changes and version history.