Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

ActSim

PyPI versionPython 3.8+License: Apache 2.0Code style: black

A Python package for actuarial risk modeling and simulation.

Features

  • 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 chainladder package
  • 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

Installation

From PyPI (recommended)

pip install ActSim

From Source

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .

Development Installation

git clone https://github.com/jzhng105/ActSim.git
cd ActSim
pip install -e .[dev]

Quick Start

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

Documentation

  • User Guide - Getting started and basic usage
  • API Reference - Detailed complete user manual covering API documentation, code examples, tutorials, contributing and development guidelines

Features in Detail

Configuration Management

# Initialize fitter with config fileconfig=load_config()

Fit Distributions

# ---------------------------------------------# 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

########################################### 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_simulations

Correlated Mutivariate Distribution Simulation

Sample 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,1

Sample 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

################################################ 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')

Development

Setting up Development Environment

# 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\activate

Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Workflow

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass (pytest)
  6. Commit your changes (git commit -m 'Add amazing feature')
  7. Push to the branch (git push origin feature/amazing-feature)
  8. Open a Pull Request

License

This project is licensed under the Apache License - see the LICENSE file for details.

Citation

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}
}

Support

Changelog

See CHANGELOG.md for a list of changes and version history.

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages