Skip to content

Quick Start

This guide will help you run your first RWA calculation in just a few minutes.

Choose Your Approach

There are two ways to run RWA calculations:

Approach Best For Guide
Interactive UI Quick analysis, exploring results, non-developers See below
Python API Automation, integration, custom workflows See below

Using the Interactive UI

The fastest way to get started is the web-based interface.

Step 1: Install with UI Support

pip install rwa-calc[ui]
# Or with uv
uv add rwa-calc --extra ui

Step 2: Start the Server

# If installed from PyPI
rwa-calc-ui

# Or from source
uv run python src/rwa_calc/ui/marimo/server.py

Step 3: Open Your Browser

Navigate to http://localhost:8000 to access:

  • RWA Calculator (/) - Run calculations on your data
  • Results Explorer (/results) - Filter and analyze results
  • Framework Reference (/reference) - View regulatory parameters

For detailed UI documentation, see the Interactive UI Guide.


Using the Python API

Basic Usage

Run a complete RWA calculation:

from datetime import date
from rwa_calc.api import CreditRiskCalc

response = CreditRiskCalc(
    data_path="/path/to/data",
    framework="CRR",
    reporting_date=date(2026, 12, 31),
).calculate()

if response.success:
    print(f"Total RWA: {response.summary.total_rwa:,.0f}")
    print(f"SA RWA:    {response.summary.total_rwa_sa:,.0f}")
    print(f"IRB RWA:   {response.summary.total_rwa_irb:,.0f}")

Complete Example

Here's a full script with validation, error handling, and export:

from datetime import date
from pathlib import Path

from rwa_calc.api import CreditRiskCalc


def calculate_rwa():
    """Calculate RWA for credit exposures."""

    calc = CreditRiskCalc(
        data_path="/path/to/data",
        framework="CRR",
        reporting_date=date(2026, 12, 31),
        permission_mode="irb",
    )

    # Run calculation
    response = calc.calculate()

    # Check for errors
    if not response.success:
        for error in response.errors:
            print(f"[{error.code}] {error.severity}: {error.message}")
        return

    # Print summary
    summary = response.summary
    print("=" * 50)
    print("RWA Calculation Results")
    print("=" * 50)
    print(f"Framework:      {response.framework}")
    print(f"Reporting Date: {response.reporting_date}")
    print(f"Exposures:      {summary.exposure_count}")
    print("-" * 50)
    print(f"Total RWA:      GBP {summary.total_rwa:,.0f}")
    print(f"  SA RWA:       GBP {summary.total_rwa_sa:,.0f}")
    print(f"  IRB RWA:      GBP {summary.total_rwa_irb:,.0f}")
    print(f"  Slotting RWA: GBP {summary.total_rwa_slotting:,.0f}")
    print(f"Avg Risk Weight: {summary.average_risk_weight:.1%}")
    print("=" * 50)

    # Print warnings if any
    if response.has_warnings:
        print(f"\n{response.warning_count} warnings:")
        for error in response.errors:
            if error.severity == "warning":
                print(f"  [{error.code}] {error.message}")

    # Export results
    export = response.to_parquet(Path("output/"))
    print(f"\nExported {export.row_count} rows to {export.files}")

    # Work with detailed results as a Polars DataFrame
    df = response.collect_results()
    print(f"\nDetailed results: {df.shape}")


if __name__ == "__main__":
    calculate_rwa()

Working with Custom Data

Specifying Data Format

By default, the calculator reads Parquet files. To use CSV:

from datetime import date
from rwa_calc.api import CreditRiskCalc

response = CreditRiskCalc(
    data_path="/path/to/csv-data",
    framework="CRR",
    reporting_date=date(2026, 12, 31),
    data_format="csv",
).calculate()

Required Data Files

The calculator expects the following files in your data directory:

File Description Required
counterparties.parquet Counterparty information Yes
facilities.parquet Credit facilities Yes
loans.parquet Individual loans/draws Yes
contingents.parquet Off-balance sheet items No
collateral.parquet Collateral holdings No
guarantees.parquet Guarantee information No
provisions.parquet Provision allocations No
ratings.parquet Credit ratings No
org_mapping.parquet Organization hierarchy No
lending_mapping.parquet Retail lending groups No

Validating Data Before Calculation

from datetime import date
from rwa_calc.api import CreditRiskCalc

calc = CreditRiskCalc(
    data_path="/path/to/data",
    framework="CRR",
    reporting_date=date(2026, 12, 31),
)

validation = calc.validate()
if validation.valid:
    print(f"Ready: {validation.found_count} files found")
else:
    print(f"Missing files: {validation.files_missing}")

Configuration Options

CRR Framework

from datetime import date
from rwa_calc.api import CreditRiskCalc

# CRR with default settings
response = CreditRiskCalc(
    data_path="/path/to/data",
    framework="CRR",
    reporting_date=date(2026, 12, 31),
).calculate()

# CRR with IRB routing (requires model_permissions input data)
response = CreditRiskCalc(
    data_path="/path/to/data",
    framework="CRR",
    reporting_date=date(2026, 12, 31),
    permission_mode="irb",
).calculate()

Basel 3.1 Framework

from datetime import date
from rwa_calc.api import CreditRiskCalc

response = CreditRiskCalc(
    data_path="/path/to/data",
    framework="BASEL_3_1",
    reporting_date=date(2027, 1, 1),
).calculate()

Permission Mode

Value Description
"standardised" All exposures use the Standardised Approach (default)
"irb" Approach routing is driven by model_permissions input data. Each model's approved approach (AIRB, FIRB, slotting) is resolved per-exposure. Exposures without a matching model permission fall back to SA.

Model permissions required for IRB mode

When permission_mode="irb", provide a model_permissions input table to control which exposures use FIRB, AIRB, or slotting. Without it, all exposures fall back to SA with a warning. See Input Schemas — Model Permissions.

Understanding Results

The CalculationResponse provides several ways to access results:

Summary Statistics

summary = response.summary
summary.total_rwa           # Total risk-weighted assets
summary.total_ead           # Total exposure at default
summary.exposure_count      # Number of exposures processed
summary.average_risk_weight # Average risk weight (RWA / EAD)

# By approach
summary.total_rwa_sa        # Standardised Approach RWA
summary.total_rwa_irb       # IRB RWA
summary.total_rwa_slotting  # Slotting RWA

# Output floor (Basel 3.1)
summary.floor_applied       # Whether output floor was binding
summary.floor_impact        # Additional RWA from output floor

Detailed Breakdown

import polars as pl

# Get as Polars DataFrame
df = response.collect_results()

# Or use lazy scanning for large result sets
lf = response.scan_results()
corporate = lf.filter(pl.col("exposure_class") == "CORPORATE").collect()

# Aggregate by any dimension
by_approach = df.group_by("approach").agg(
    pl.col("rwa").sum().alias("total_rwa"),
    pl.col("ead").sum().alias("total_ead"),
)

Export Results

from pathlib import Path

# To Parquet
response.to_parquet(Path("output/"))

# To CSV
response.to_csv(Path("output/"))

# To Excel (requires xlsxwriter)
response.to_excel(Path("output/results.xlsx"))

# To COREP regulatory templates (requires xlsxwriter)
response.to_corep(Path("output/corep.xlsx"))

Error Handling

The calculator accumulates errors rather than failing fast:

# Check overall success
if not response.success:
    print("Calculation failed")

# Check for errors
if response.has_errors:
    for error in response.errors:
        if error.severity in ("error", "critical"):
            print(f"[{error.code}] {error.message}")

# Check for warnings
if response.has_warnings:
    for error in response.errors:
        if error.severity == "warning":
            print(f"Warning [{error.code}]: {error.message}")

Advanced: Pipeline API

For users who need to customise individual pipeline components, the low-level pipeline API provides direct access to the orchestrator:

from datetime import date
from rwa_calc.engine.pipeline import create_pipeline
from rwa_calc.contracts.config import CalculationConfig

# Create configuration
config = CalculationConfig.crr(reporting_date=date(2026, 12, 31))

# Create and run the pipeline
pipeline = create_pipeline()
result = pipeline.run(config)

# Access the aggregated result bundle directly
print(f"Total RWA: {result.total_rwa:,.2f}")

This gives you access to the full PipelineOrchestrator and AggregatedResultBundle, which is useful for custom loaders, alternative data sources, or when integrating into an existing data pipeline. See the Pipeline API Reference for details.

Next Steps