Skip to content

RiskPY API Reference

Reference for the compiled core — the classes you import straight from riskpy — and the UnderwritingApp GUI. The Python modelling layers have their own pages: Monte Carlo, Quant, Life, Reserving, Rates and Credit.

pip install open-riskpy            # the compiled core
pip install "open-riskpy[gui]"     # + Matplotlib and NumPy, for UnderwritingApp and the NumPy snippets below

Not yet documented on this page: ExperienceRating, ExposureRating, Field, the simulate_economic_path, simulate_health_claims and simulate_catastrophe_loss scenarios, and RiskEngine.export_batch_to_excel.


Table of Contents


FactorModel

A declarative, multiplicative rating engine. Define pricing rules as factors — the C++ engine applies them instantly across any number of policies.

Constructor

from riskpy import FactorModel

model = FactorModel(initial_base_rate=1000.0)
Parameter Type Description
initial_base_rate float The starting premium before any factors are applied. Default: 0.0

Methods

set_base_rate(rate)

Updates the base rate after construction.

model.set_base_rate(1500.0)
Parameter Type Description
rate float New base premium amount

add_multiplier(field_name, exact_value, multiplier)

Adds a categorical factor rule. When the input field exactly matches the value, the premium is multiplied by the factor.

model.add_multiplier("state", "CA", 2.0)   # California = 2x
model.add_multiplier("state", "FL", 3.0)   # Florida = 3x (hurricane risk)
model.add_multiplier("vehicle_type", "Sports Car", 2.5)
Parameter Type Description
field_name str The name of the input field to match against
exact_value str The exact string value that triggers this multiplier
multiplier float The factor to multiply the premium by (e.g., 2.0 = double)

add_numeric_band_multiplier(field_name, min_val, max_val, multiplier)

Adds a continuous band factor. When the numeric input falls within [min_val, max_val], the multiplier is applied.

model.add_numeric_band_multiplier("driver_age", 16, 25, 2.0)   # Young driver surcharge
model.add_numeric_band_multiplier("driver_age", 26, 65, 1.0)   # Standard rate
model.add_numeric_band_multiplier("driver_age", 66, 99, 1.3)   # Senior surcharge
Parameter Type Description
field_name str The name of the numeric input field
min_val float Lower bound of the band (inclusive)
max_val float Upper bound of the band (inclusive)
multiplier float The factor to apply when the value falls in this band

calculate(inputs)

Evaluates all rules against a dictionary of inputs and returns the final premium.

premium = model.calculate({"state": "CA", "driver_age": 22.0})
# Result: 1000.0 × 2.0 (CA) × 2.0 (age 16-25) = $4,000.00
Parameter Type Description
inputs dict[str, str \| float] A dictionary mapping field names to their values

Returns: float — The calculated premium after all matching factors are applied.


MonteCarloSimulator

High-performance stochastic simulation engine running natively in C++. Construct it with the trial count (and an optional seed), then call the scenario methods.

Methods

MonteCarloSimulator(trials, seed=0).simulate_aggregate_loss(expected_frequency, expected_severity_mu, severity_sigma)

Simulates aggregate insurance losses for Property & Casualty portfolios. Each trial generates a random number of claims (Poisson distributed) with random severity amounts (Lognormal distributed), then sums them.

from riskpy import MonteCarloSimulator

results = MonteCarloSimulator(trials=100000).simulate_aggregate_loss(
    expected_frequency=5.0,
    expected_severity_mu=10.0,
    severity_sigma=1.5
)

# results is a list of 100,000 floats, each representing one simulated year's total losses
import numpy as np
var_99 = np.percentile(results, 99)
print(f"99% Value-at-Risk: ${var_99:,.0f}")
Parameter Type Description
expected_frequency float Average number of claims per period — the λ parameter for Poisson distribution
expected_severity_mu float Mean of the log of severity — the μ parameter for Lognormal distribution
severity_sigma float Standard deviation of the log of severity — the σ parameter for Lognormal distribution

Returns: list[float] — Array of aggregated loss amounts, one per trial.

Use cases: Catastrophe modeling, reinsurance pricing, capital requirements (Solvency II, IFRS 17), determining reserves.


MonteCarloSimulator(trials, seed=0).simulate_life_portfolio(policy_count, base_mortality_rate, shock_volatility, death_benefit)

Simulates total mortality claims for a life insurance portfolio. Each trial applies a stochastic shock to the base mortality rate, then determines how many policyholders die and calculates total claims.

results = MonteCarloSimulator(trials=50000).simulate_life_portfolio(
    policy_count=10000,
    base_mortality_rate=0.001,
    shock_volatility=0.2,
    death_benefit=500000.0
)

# results is a list of 50,000 total claim amounts
expected_claims = np.mean(results)
print(f"Expected annual claims: ${expected_claims:,.0f}")
Parameter Type Description
policy_count int Number of policies in the portfolio
base_mortality_rate float Base probability of death per policyholder per period (e.g., 0.001 = 0.1%)
shock_volatility float Standard deviation of the multiplicative mortality shock (Normal distribution centered at 1.0)
death_benefit float Payout amount per death claim

Returns: list[float] — Array of total portfolio claim amounts, one per trial.

Use cases: Life portfolio risk assessment, pandemic scenario testing, mortality assumption validation.


ActuarialMath

Core actuarial formulas implemented in C++ for maximum precision and speed. All methods are static.

Methods

present_value(rate, periods, payment)

Calculates the present value of an ordinary annuity — the current worth of a series of future payments.

from riskpy import ActuarialMath

# What is $50,000/year for 20 years worth today at 5% discount?
pv = ActuarialMath.present_value(rate=0.05, periods=20, payment=50000)
print(f"Present value: ${pv:,.2f}")  # $623,110.52
Parameter Type Description
rate float Discount rate per period (e.g., 0.05 for 5%)
periods int Number of payment periods
payment float Payment amount per period

Returns: float — Present value of the annuity.


future_value(rate, periods, payment)

Calculates the future value of an ordinary annuity — what a series of payments will grow to.

fv = ActuarialMath.future_value(rate=0.07, periods=30, payment=10000)
print(f"Future value: ${fv:,.2f}")
Parameter Type Description
rate float Interest rate per period
periods int Number of payment periods
payment float Payment amount per period

Returns: float — Future value of the annuity.


calculate_loss_ratio(incurred_losses, earned_premium)

Calculates the loss ratio — a critical P&C insurance KPI.

lr = ActuarialMath.calculate_loss_ratio(incurred_losses=750000, earned_premium=1000000)
print(f"Loss ratio: {lr:.1%}")  # 75.0%
Parameter Type Description
incurred_losses float Total incurred losses
earned_premium float Total earned premium

Returns: float — Loss ratio (e.g., 0.75 for 75%).


lookup_mortality_rate(age)

Returns an illustrative mortality rate (qx) from a coarse banded step table loosely shaped like CSO 2001 — it is not the published table. For real life tables use riskpy.life.

qx = ActuarialMath.lookup_mortality_rate(age=65)
print(f"Mortality rate at age 65: {qx:.4f}")
Parameter Type Description
age int Age of the insured (integer)

Returns: float — Probability of death within one year (qx).


UnderwritingApp

The high-level Python class that provides a complete GUI application. It wraps the C++ engine, Excel exporter, and Monte Carlo simulator into an interactive Tkinter desktop app.

Constructor

from riskpy import UnderwritingApp

app = UnderwritingApp(title="My Pricing Tool", excel_template="template.xlsx")
Parameter Type Description
title str Window title for the GUI. Default: "Actuarial Underwriter"
excel_template str Accepted but currently ignored: every export creates a new workbook rather than filling a template. Default: "corporate_layout.xlsx"

Methods

add_field(name, label, excel_col, choices=None)

Adds an input field to the GUI form and maps it to an Excel column.

app.add_field("state", "Location State", "A", choices=["NY", "CA", "FL"])
app.add_field("age", "Driver Age", "B")  # free-text numeric input
Parameter Type Description
name str Internal field identifier
label str Human-readable label shown in the GUI
excel_col str Excel column letter for export (e.g., "A", "B")
choices list[str] or None If provided, renders a dropdown. If None, renders a text input

set_factor_model(factor_model)

Connects a FactorModel instance as the calculation engine.

model = FactorModel(initial_base_rate=500.0)
model.add_multiplier("state", "FL", 3.0)
app.set_factor_model(model)
Parameter Type Description
factor_model FactorModel A configured FactorModel instance

set_logic(logic_func)

Sets a custom Python function as the calculation logic (alternative to FactorModel).

def my_pricing(inputs):
    base = 1000
    if inputs.get("state") == "CA":
        base *= 2
    return base

app.set_logic(my_pricing)
Parameter Type Description
logic_func callable A function that accepts dict inputs and returns a float premium

calculate_headless(inputs)

Runs a single calculation without opening the GUI.

premium = app.calculate_headless({"state": "CA", "age": 22.0})
print(f"${premium:,.2f}")
Parameter Type Description
inputs dict Field name to value mapping

Returns: float — Calculated premium.


set_premium_column(excel_col, label="Final Premium")

Maps the calculated premium to an Excel column. Without it, exports contain the input columns but no premium.

app.set_premium_column("E", "Premium")
Parameter Type Description
excel_col str Excel column letter for the premium
label str Header text. Default: "Final Premium"

export_excel_headless(filename="policy_quote.xlsx")

Writes the most recent calculate_headless inputs and premium to an Excel file, without the GUI.

app.calculate_headless({"state": "CA", "age": 22.0})
app.export_excel_headless("quote.xlsx")
Parameter Type Description
filename str Output path. Default: "policy_quote.xlsx"

calculate_batch(csv_filepath, output_filename)

Processes an entire CSV file of policy inputs and exports the mapped columns — the inputs, and the premium if set_premium_column was called — to Excel.

total, count = app.calculate_batch("policies.csv", "results.xlsx")
print(f"Processed {count} policies. Total book premium: ${total:,.2f}")
Parameter Type Description
csv_filepath str Path to the CSV input file
output_filename str Path for the Excel output file. Default: "batch_policy_quotes.xlsx"

Returns: tuple[float, int] — (total premium, number of records processed).


run(export_filename)

Launches the interactive Tkinter GUI with two tabs: Pricing & Rating, and Monte Carlo Predictor.

app.run()
Parameter Type Description
export_filename str Default filename for single-quote Excel exports. Default: "policy_quote.xlsx"

LossTriangle

Chain-ladder development factors, ultimate losses, and IBNR reserves.

from riskpy import LossTriangle

t = LossTriangle()
t.add_origin_year(2020, [1000.0, 1500.0, 1800.0, 2000.0])
t.add_origin_year(2021, [1200.0, 1800.0, 2160.0])
print(t.get_development_factors())
print(t.get_ultimate_losses())
print(t.get_ibnr_reserves())
Method Returns Description
add_origin_year(year, cumulative_payments) None Append an origin year row (finite, non-negative)
get_development_factors() list[float] Weighted age-to-age LDFs
get_ultimate_losses() list[float] Ultimate per origin year
get_ibnr_reserves() list[float] Ultimate − latest diagonal (≥ 0)
get_origin_year_count() int Number of origin years
get_development_period_count() int Max development periods

RateAnalyzer

On-level premiums, trend, combined ratio, and indicated rate change.

from riskpy import RateAnalyzer

ra = RateAnalyzer(target_combined_ratio=1.0, expense_ratio=0.30)
print(ra.required_rate_change(0.84))          # 0.20
print(ra.on_level_premiums([100, 110], [0.05, 0.0]))
print(ra.trend_factor(0.05, 2.0))
Method Description
on_level_factor(rate_changes) Product of (1 + change)
on_level_premiums(earned_premiums, rate_changes) Bring historical EP to current rate level (O(n))
rate_change_impact(old_premium, new_premium) (new/old) - 1
combined_ratio(loss_ratio) LR + expense ratio
required_rate_change(current_loss_ratio) Indicated rate change to hit target CR
permissible_loss_ratio() Target CR − expense ratio
trend_factor(annual_trend, years) (1 + trend)^years
loss_cost_rate(incurred_losses, earned_exposure) Pure premium

FourierTransform

Analytic Fourier utilities for aggregate-loss modeling (no Monte Carlo sampling error for the compound-Poisson PMF).

from riskpy import FourierTransform

re, im = FourierTransform.fft([1.0, 2.0, 3.0, 4.0], [0.0, 0.0, 0.0, 0.0])
back_re, back_im = FourierTransform.ifft(re, im)

conv = FourierTransform.convolve([1.0, 2.0, 3.0], [4.0, 5.0])

# Compound Poisson: severity always 1 → S ~ Poisson(λ)
pmf = FourierTransform.compound_poisson_pmf(
    severity_pmf=[0.0, 1.0],
    expected_frequency=2.0,
    grid_size=64,   # power of 2, or 0 for auto
)
Method Description
fft(real, imag) Forward DFT; zero-pads to next power of 2; empty → empty
ifft(real, imag) Inverse DFT (1/N normalized)
convolve(a, b) Linear convolution, length len(a)+len(b)-1
compound_poisson_pmf(severity_pmf, expected_frequency, grid_size=0) Aggregate PMF via FFT; severity auto-normalized

Notes: Inputs must be finite. Severity mass must be positive (auto-normalized to a PMF). Output PMF is re-normalized to sum ≈ 1.


RiskEngine

Low-level C++ calculation orchestrator. Most users should use UnderwritingApp instead, which wraps this class. Exposed for advanced use cases.

from riskpy import RiskEngine, Field

engine = RiskEngine()
engine.add_field(Field(name="age", label="Age", type="float"))
engine.set_math_logic(my_function)
result = engine.execute({"age": 25.0})

Methods

Method Parameters Returns Description
add_field(field) Field None Registers an input field
get_fields() — list[Field] Returns all registered fields
set_math_logic(func) callable None Sets the pricing function
attach_exporter(exporter) ExcelExporter None Connects Excel output
execute(inputs) dict float Runs calculation
export_to_excel(filename) str None Writes results to Excel

ExcelExporter

Writes calculation results to binary .xlsx files using the C++ OpenXLSX library (bypasses Python entirely for speed).

from riskpy import ExcelExporter

exporter = ExcelExporter(template="my_template.xlsx")  # template is accepted but currently ignored
exporter.map_column("A", "state", "State")
exporter.map_column("B", "age", "Driver Age")

Methods

Method Parameters Returns Description
map_column(col, field, label) str, str, str None Maps a field to an Excel column