Skip to main content

Model risk management framework for insurance pricing models

Project description

insurance-mrm

Model risk management framework for insurance pricing models.

The problem

Most UK insurers govern their pricing models with Word documents and Excel registers. A validation report is produced once at model launch, filed away, and referenced occasionally. Monitoring evidence (if it exists) lives in a separate tracker maintained by the pricing team. There is no audit trail connecting monitoring outputs to governance sign-offs.

This is not a criticism of any specific firm — it is a description of current practice across the market. The PRA's 2026 supervision priorities letter called out "gaps between assumed and realised profitability" for general insurers. PRA SS1/23 is expected to extend to insurers by 2026-2027. The current documentation approach will not survive a PRA model risk review.

insurance-mrm is the governance layer that sits on top of statistical validation and monitoring. It does not run statistical tests. Those are handled by insurance-validation (point-in-time validation reports) and insurance-monitoring (ongoing operational monitoring). What insurance-mrm provides is:

  • A model card format with the fields a Model Risk Committee actually needs: assumptions register with risk ratings per assumption, explicit not-intended-for list, monitoring plan with named owner and trigger thresholds
  • An objective risk tier scoring engine (0-100 composite score across 6 dimensions) that produces a defensible tier assignment with a verbose rationale string — not a judgment call
  • A persistent model inventory backed by a plain JSON file, queryable by tier, status, owner, and review due date
  • An executive committee report (HTML and JSON) that pulls together model identity, tier, validation status, monitoring summary, material assumptions, outstanding issues, and sign-off chain into a 2-3 page governance pack

Installation

pip install insurance-mrm

No mandatory dependencies beyond the standard library. Optional: insurance-validation and insurance-monitoring for richer integration.

Quickstart

from insurance_mrm import (
    ModelCard, Assumption, Limitation,
    ModelInventory, RiskTierScorer, GovernanceReport,
)

# 1. Build a model card
card = ModelCard(
    model_id='motor-freq-tppd-v2',
    model_name='Motor TPPD Frequency',
    version='2.1.0',
    model_class='pricing',
    intended_use='Frequency pricing for private motor. Not for commercial motor, fleet, or reserving.',
    not_intended_for=['Commercial motor', 'Fleet', 'Reserving', 'Capital'],
    target_variable='claim_count',
    distribution_family='Poisson',
    model_type='CatBoost',
    rating_factors=['driver_age', 'vehicle_age', 'annual_mileage', 'region'],
    training_data_period=('2019-01-01', '2023-12-31'),
    developer='Pricing Team',
    champion_challenger_status='champion',
    gwp_impacted=125_000_000,
    customer_facing=True,
    regulatory_use=False,
    assumptions=[
        Assumption(
            description='Claim frequency stationarity since 2022',
            risk='MEDIUM',
            mitigation='Quarterly A/E monitoring, PSI alert at >0.25',
        ),
        Assumption(
            description='Region as proxy for road density and theft risk',
            risk='LOW',
        ),
    ],
    limitations=[
        Limitation(
            description='Performance degrades for vehicles >10 years (thin training data)',
            impact='Higher prediction variance for this segment',
            population_at_risk='~8% of book',
        ),
    ],
    outstanding_issues=['VIF check on driver_age x annual_mileage pending'],
    approved_by=['Chief Actuary', 'Model Risk Committee'],
    approval_date='2024-10-15',
    approval_conditions='Subject to quarterly A/E monitoring',
    next_review_date='2025-10-15',
    monitoring_owner='Sarah Ahmed, Head of Pricing Analytics',
    monitoring_frequency='Quarterly',
    monitoring_triggers={'psi_score': 0.25, 'ae_ratio_deviation': 0.10, 'gini_drop_pct': 0.05},
)

# 2. Score the risk tier
scorer = RiskTierScorer()
tier = scorer.score(
    gwp_impacted=125_000_000,
    model_complexity='high',          # 'low' | 'medium' | 'high'
    deployment_status='champion',     # 'champion' | 'challenger' | 'shadow' | 'development' | 'retired'
    regulatory_use=False,
    external_data=False,
    customer_facing=True,
    validation_months_ago=6.0,
    drift_triggers_last_year=0,
)
print(f"Tier {tier.tier} ({tier.tier_label}): {tier.score:.1f}/100")
print(tier.rationale)

# 3. Register in the inventory
inventory = ModelInventory('mrm_registry.json')
inventory.register(card, tier)

due = inventory.due_for_review(within_days=60)
for model in due:
    print(f"{model['model_name']} — review due {model['next_review_date']}")

# 4. Generate the governance pack
report = GovernanceReport(
    card=card,
    tier=tier,
    validation_results={
        'overall_rag': 'GREEN',
        'run_id': 'a1b2c3d4-uuid',
        'run_date': '2024-10-01',
        'gini': 0.42,
        'ae_ratio': 1.01,
        'psi_score': 0.07,
    },
    monitoring_results={
        'period': '2025-Q3',
        'ae_ratio': 1.02,
        'psi_score': 0.06,
        'recommendation': 'Continue',
    },
)
report.save_html('motor_freq_mrm_pack.html')

Risk tier scoring

The scorer produces a 0-100 composite score across 6 dimensions. Weights sum to 100 and are configurable.

Dimension What it measures Max pts (default)
Materiality GWP influenced by the model 25
Complexity Model architecture and feature count 20
Data quality Use of external data sources 10
Validation coverage Months since last independent validation 10
Drift history Monitoring trigger events in last 12 months 10
Regulatory exposure Production status + regulatory use + customer-facing pricing 25

Tier thresholds (defaults):

Score Tier Label Review Sign-off
>= 60 1 Critical Annual Model Risk Committee
30-59 2 High 18 months Chief Actuary
< 30 3 Medium 24 months Head of Pricing

Override weights and thresholds at construction:

scorer = RiskTierScorer(
    weights={
        'materiality': 35, 'complexity': 20, 'data_quality': 5,
        'validation_coverage': 15, 'drift_history': 10, 'regulatory_exposure': 15,
    },
    thresholds={1: 65, 2: 35, 3: 0},
)

Model inventory

inventory = ModelInventory('mrm_registry.json')

# Register
inventory.register(card, tier)

# Query
rows = inventory.list()
rows = inventory.list(status='champion')
rows = inventory.list(tier=1)
rows = inventory.list(owner='Sarah')
due = inventory.due_for_review(within_days=60)
overdue = inventory.overdue()

# Update after validation
inventory.update_validation(
    model_id='motor-freq-tppd-v2',
    validation_date='2025-10-01',
    overall_rag='GREEN',
    next_review_date='2026-10-01',
    run_id='uuid-from-insurance-validation',
)

# Audit log
inventory.log_event(
    model_id='motor-freq-tppd-v2',
    event_type='monitoring_trigger',
    description='PSI exceeded 0.25 on driver_age feature',
)

print(inventory.summary())

The inventory file is plain JSON and git-auditable. Treat it as source-controlled documentation.

Regulatory context

Designed with PRA SS1/23 Principles 1 and 5 in mind. SS1/23 is currently scoped to banks but is expected to extend to insurers by 2026-2027. The tier scoring rubric and model card fields align with SS1/23 expectations.

FCA Consumer Duty (PRIN 2A.9) requires firms to regularly evidence customer outcomes. The monitoring plan fields and trigger thresholds on the model card support this documentation requirement.

Part of the Burning Cost ecosystem

insurance-mrm is library 28 in the Burning Cost portfolio. It is the governance wrapper for:

  • insurance-validation — point-in-time technical validation reports
  • insurance-monitoring — ongoing operational monitoring

A team using all three has a complete, auditable, PRA-aligned pricing model governance workflow in Python.

Licence

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

insurance_mrm-0.1.0.tar.gz (40.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

insurance_mrm-0.1.0-py3-none-any.whl (28.1 kB view details)

Uploaded Python 3

File details

Details for the file insurance_mrm-0.1.0.tar.gz.

File metadata

  • Download URL: insurance_mrm-0.1.0.tar.gz
  • Upload date:
  • Size: 40.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for insurance_mrm-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2ea235443fbf069987d24c4fcf197b698940f88688eab4fb1e0631b5328c1830
MD5 6ade215c34c983572fbf0c73621ec3f7
BLAKE2b-256 cfb3b6ece442cfdf5426b62ce1071da1178a13d59fb727ccd449bfa197f17913

See more details on using hashes here.

File details

Details for the file insurance_mrm-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: insurance_mrm-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 28.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for insurance_mrm-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1516dea9b8d55aa7e1dc79bbbe90e0b965d5aae80e94ca546814494737e862cd
MD5 4f634285ae771df5b3caadf1ae9807f7
BLAKE2b-256 e5b43e7b4ce5932fe485827ccac3d2a32324620e3dc8a740d71bc275ec207ae8

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page