Case Study 1: Auto Insurance Premium Rating Engine
Background
Midwest Mutual Insurance Company (MMIC) is a regional property and casualty insurer writing approximately $620 million in personal auto insurance premiums across six Midwestern states. The company insures over 400,000 vehicles and processes more than 2 million policy transactions annually, including new business quotes, renewals, endorsements, and cancellations.
MMIC's auto insurance premium rating engine is the heart of its policy administration system. Every time a prospective customer requests a quote, a current policyholder adds a vehicle, or a policy renews, the rating engine calculates the premium by combining a base rate with multiple risk-based rating factors. The rating engine runs on an IBM z/OS mainframe and is written entirely in COBOL, processing both real-time CICS inquiries from agents and nightly batch rating runs for bulk renewals.
The rating engine uses a table-driven architecture: all rates and factors are stored in external files loaded into COBOL tables at program initialization, rather than being hardcoded. This design allows MMIC's actuarial department to update rates without any code changes. When regulators approve a new rate filing, the actuaries update the rate table files, and the next execution of the rating engine automatically applies the new rates.
This case study presents a complete COBOL implementation of MMIC's auto insurance premium rating engine, demonstrating table-driven rate calculations with multiple risk factors including driver age, vehicle type, driving record, territory, and coverage level.
Business Requirements
The rating engine must satisfy the following requirements:
-
Multi-factor rating: Calculate premiums by multiplying a base rate by five independent rating factors: driver age, vehicle classification, driving record, territory, and coverage level. Each factor is looked up from a table.
-
Multiple coverage lines: Rate three coverage lines separately -- liability, collision, and comprehensive -- each with its own base rate and applicable factors.
-
Discount and surcharge application: After the base calculation, apply eligible discounts (multi-car, good student, defensive driving) and surcharges (at-fault accident, moving violation).
-
Premium bounds checking: Ensure the calculated premium does not fall below a minimum premium floor or exceed a regulatory maximum.
-
Auditability: The rating engine must produce a detailed rating worksheet showing every factor applied and every intermediate calculation, enabling regulatory examiners to trace any premium from base rate to final amount.
Rating Factor Tables
The following tables define the rating factors used by MMIC. In production, these are loaded from VSAM files. For this program, they are initialized in WORKING-STORAGE using VALUE clauses.
Driver Age Factors:
| Age Range | Factor Code | Factor |
|---|---|---|
| 16-19 | 01 | 2.15 |
| 20-24 | 02 | 1.55 |
| 25-29 | 03 | 1.15 |
| 30-64 | 04 | 1.00 |
| 65-74 | 05 | 1.10 |
| 75+ | 06 | 1.30 |
Vehicle Classification Factors:
| Class | Factor Code | Factor |
|---|---|---|
| Sedan | SD | 1.00 |
| SUV | SV | 1.12 |
| Truck | TK | 1.05 |
| Sports | SP | 1.40 |
| Luxury | LX | 1.55 |
| Van | VN | 0.95 |
Driving Record Factors (points in last 3 years):
| Points | Factor Code | Factor |
|---|---|---|
| 0 | 00 | 0.90 |
| 1-2 | 01 | 1.00 |
| 3-4 | 02 | 1.20 |
| 5-6 | 03 | 1.45 |
| 7-9 | 04 | 1.75 |
| 10+ | 05 | 2.25 |
Territory Factors (by rating territory):
| Territory | Description | Factor |
|---|---|---|
| 01 | Urban core | 1.35 |
| 02 | Urban fringe | 1.20 |
| 03 | Suburban | 1.05 |
| 04 | Small city | 0.95 |
| 05 | Rural | 0.85 |
Coverage Level Factors:
| Level | Description | Liability | Collision | Comprehensive |
|---|---|---|---|---|
| BASIC | State minimum limits | 0.55 | N/A | N/A |
| STAND | 50/100/50 with $1000 deductible | 1.00 | 1.00 | 1.00 |
| PLUS | 100/300/100 with $500 deductible | 1.30 | 1.15 | 1.10 |
| PREM | 250/500/250 with $250 deductible | 1.65 | 1.35 | 1.25 |
Complete COBOL Program
IDENTIFICATION DIVISION.
PROGRAM-ID. AUTORATE.
AUTHOR. MMIC RATING SYSTEMS.
DATE-WRITTEN. 2024-08-15.
*================================================================*
* PROGRAM: AUTORATE - AUTO INSURANCE PREMIUM RATING ENGINE *
* *
* PURPOSE: Calculate auto insurance premiums using table-driven *
* multi-factor rating. Produces a detailed rating *
* worksheet for each policy showing all factors applied.*
* *
* ARCHITECTURE: Table-driven. All rates and factors are loaded *
* into COBOL tables at initialization. No rates are *
* hardcoded in the calculation logic. When rates change, *
* only the table data is updated; the program is not *
* modified or recompiled. *
* *
* INPUT: POLYIN - Policy/vehicle/driver data *
* OUTPUT: RATEOUT - Rating worksheet report *
*================================================================*
ENVIRONMENT DIVISION.
CONFIGURATION SECTION.
REPOSITORY.
FUNCTION ALL INTRINSIC.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT POLICY-INPUT
ASSIGN TO POLYIN
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-INPUT-STATUS.
SELECT RATING-REPORT
ASSIGN TO RATEOUT
ORGANIZATION IS LINE SEQUENTIAL
FILE STATUS IS WS-REPORT-STATUS.
DATA DIVISION.
FILE SECTION.
FD POLICY-INPUT
RECORDING MODE IS F
RECORD CONTAINS 120 CHARACTERS.
01 POLICY-INPUT-REC.
05 PI-POLICY-NUMBER PIC X(10).
05 PI-INSURED-NAME PIC X(25).
05 PI-DRIVER-AGE PIC 9(03).
05 PI-VEHICLE-CLASS PIC X(02).
05 PI-DRIVING-POINTS PIC 9(02).
05 PI-TERRITORY PIC X(02).
05 PI-COVERAGE-LEVEL PIC X(05).
05 PI-MULTI-CAR-FLAG PIC X(01).
88 PI-MULTI-CAR VALUE 'Y'.
05 PI-GOOD-STUDENT-FLAG PIC X(01).
88 PI-GOOD-STUDENT VALUE 'Y'.
05 PI-DEFENSIVE-DRV-FLAG PIC X(01).
88 PI-DEFENSIVE-DRV VALUE 'Y'.
05 PI-AT-FAULT-CLAIMS PIC 9(01).
05 PI-MOVING-VIOLATIONS PIC 9(02).
05 FILLER PIC X(63).
FD RATING-REPORT
RECORDING MODE IS F
RECORD CONTAINS 132 CHARACTERS.
01 REPORT-LINE PIC X(132).
WORKING-STORAGE SECTION.
*----------------------------------------------------------------*
* FILE STATUS AND CONTROL *
*----------------------------------------------------------------*
01 WS-FILE-STATUS.
05 WS-INPUT-STATUS PIC X(02).
05 WS-REPORT-STATUS PIC X(02).
01 WS-EOF-FLAG PIC X(01) VALUE 'N'.
88 END-OF-FILE VALUE 'Y'.
88 NOT-END-OF-FILE VALUE 'N'.
*----------------------------------------------------------------*
* DRIVER AGE FACTOR TABLE *
*----------------------------------------------------------------*
01 WS-AGE-TABLE-DATA.
05 FILLER PIC X(10) VALUE '0160192.15'.
05 FILLER PIC X(10) VALUE '0200241.55'.
05 FILLER PIC X(10) VALUE '0250291.15'.
05 FILLER PIC X(10) VALUE '0300641.00'.
05 FILLER PIC X(10) VALUE '0650741.10'.
05 FILLER PIC X(10) VALUE '0750991.30'.
01 WS-AGE-TABLE REDEFINES WS-AGE-TABLE-DATA.
05 WS-AGE-ENTRY OCCURS 6 TIMES.
10 WS-AGE-MIN PIC 9(03).
10 WS-AGE-MAX PIC 9(03).
10 WS-AGE-FACTOR PIC 9V99.
01 WS-AGE-TABLE-SIZE PIC 9(02) VALUE 6.
*----------------------------------------------------------------*
* VEHICLE CLASSIFICATION FACTOR TABLE *
*----------------------------------------------------------------*
01 WS-VEH-TABLE-DATA.
05 FILLER PIC X(06) VALUE 'SD1.00'.
05 FILLER PIC X(06) VALUE 'SV1.12'.
05 FILLER PIC X(06) VALUE 'TK1.05'.
05 FILLER PIC X(06) VALUE 'SP1.40'.
05 FILLER PIC X(06) VALUE 'LX1.55'.
05 FILLER PIC X(06) VALUE 'VN0.95'.
01 WS-VEH-TABLE REDEFINES WS-VEH-TABLE-DATA.
05 WS-VEH-ENTRY OCCURS 6 TIMES.
10 WS-VEH-CODE PIC X(02).
10 WS-VEH-FACTOR PIC 9V99.
01 WS-VEH-TABLE-SIZE PIC 9(02) VALUE 6.
*----------------------------------------------------------------*
* DRIVING RECORD FACTOR TABLE *
*----------------------------------------------------------------*
01 WS-DRV-TABLE-DATA.
05 FILLER PIC X(08) VALUE '00000.90'.
05 FILLER PIC X(08) VALUE '01021.00'.
05 FILLER PIC X(08) VALUE '03041.20'.
05 FILLER PIC X(08) VALUE '05061.45'.
05 FILLER PIC X(08) VALUE '07091.75'.
05 FILLER PIC X(08) VALUE '10992.25'.
01 WS-DRV-TABLE REDEFINES WS-DRV-TABLE-DATA.
05 WS-DRV-ENTRY OCCURS 6 TIMES.
10 WS-DRV-PTS-MIN PIC 9(02).
10 WS-DRV-PTS-MAX PIC 9(02).
10 WS-DRV-FACTOR PIC 9V99.
01 WS-DRV-TABLE-SIZE PIC 9(02) VALUE 6.
*----------------------------------------------------------------*
* TERRITORY FACTOR TABLE *
*----------------------------------------------------------------*
01 WS-TERR-TABLE-DATA.
05 FILLER PIC X(06) VALUE '011.35'.
05 FILLER PIC X(06) VALUE '021.20'.
05 FILLER PIC X(06) VALUE '031.05'.
05 FILLER PIC X(06) VALUE '040.95'.
05 FILLER PIC X(06) VALUE '050.85'.
01 WS-TERR-TABLE REDEFINES WS-TERR-TABLE-DATA.
05 WS-TERR-ENTRY OCCURS 5 TIMES.
10 WS-TERR-CODE PIC X(02).
10 WS-TERR-FACTOR PIC 9V99.
01 WS-TERR-TABLE-SIZE PIC 9(02) VALUE 5.
*----------------------------------------------------------------*
* COVERAGE LEVEL FACTOR TABLE *
* Each entry has: code(5) + liability(4) + collision(4) + *
* comprehensive(4) = 17 characters *
*----------------------------------------------------------------*
01 WS-COV-TABLE-DATA.
05 FILLER PIC X(17) VALUE 'BASIC0.550.000.00'.
05 FILLER PIC X(17) VALUE 'STAND1.001.001.00'.
05 FILLER PIC X(17) VALUE 'PLUS 1.301.151.10'.
05 FILLER PIC X(17) VALUE 'PREM 1.651.351.25'.
01 WS-COV-TABLE REDEFINES WS-COV-TABLE-DATA.
05 WS-COV-ENTRY OCCURS 4 TIMES.
10 WS-COV-CODE PIC X(05).
10 WS-COV-LIAB-FAC PIC 9V99.
10 WS-COV-COLL-FAC PIC 9V99.
10 WS-COV-COMP-FAC PIC 9V99.
01 WS-COV-TABLE-SIZE PIC 9(02) VALUE 4.
*----------------------------------------------------------------*
* BASE RATES BY COVERAGE LINE *
*----------------------------------------------------------------*
01 WS-BASE-RATES.
05 WS-BASE-LIABILITY PIC S9(5)V99 COMP-3
VALUE 650.00.
05 WS-BASE-COLLISION PIC S9(5)V99 COMP-3
VALUE 420.00.
05 WS-BASE-COMPREHENSIVE PIC S9(5)V99 COMP-3
VALUE 185.00.
*----------------------------------------------------------------*
* DISCOUNT AND SURCHARGE RATES *
*----------------------------------------------------------------*
01 WS-DISC-SURCH-RATES.
05 WS-MULTI-CAR-DISC PIC S9V99 COMP-3
VALUE 0.10.
05 WS-GOOD-STUDENT-DISC PIC S9V99 COMP-3
VALUE 0.08.
05 WS-DEFENSIVE-DRV-DISC PIC S9V99 COMP-3
VALUE 0.05.
05 WS-AT-FAULT-SURCH PIC S9V99 COMP-3
VALUE 0.20.
05 WS-VIOLATION-SURCH PIC S9V99 COMP-3
VALUE 0.10.
*----------------------------------------------------------------*
* PREMIUM BOUNDS *
*----------------------------------------------------------------*
01 WS-PREMIUM-BOUNDS.
05 WS-MIN-PREMIUM PIC S9(5)V99 COMP-3
VALUE 250.00.
05 WS-MAX-PREMIUM PIC S9(5)V99 COMP-3
VALUE 25000.00.
*----------------------------------------------------------------*
* RATING CALCULATION FIELDS *
*----------------------------------------------------------------*
01 WS-RATING-FIELDS.
05 WS-FOUND-AGE-FAC PIC S9V99 COMP-3.
05 WS-FOUND-VEH-FAC PIC S9V99 COMP-3.
05 WS-FOUND-DRV-FAC PIC S9V99 COMP-3.
05 WS-FOUND-TERR-FAC PIC S9V99 COMP-3.
05 WS-FOUND-LIAB-FAC PIC S9V99 COMP-3.
05 WS-FOUND-COLL-FAC PIC S9V99 COMP-3.
05 WS-FOUND-COMP-FAC PIC S9V99 COMP-3.
01 WS-COVERAGE-PREMIUMS.
05 WS-LIAB-PREMIUM PIC S9(5)V99 COMP-3.
05 WS-COLL-PREMIUM PIC S9(5)V99 COMP-3.
05 WS-COMP-PREMIUM PIC S9(5)V99 COMP-3.
05 WS-SUBTOTAL-PREMIUM PIC S9(5)V99 COMP-3.
01 WS-DISCOUNT-FIELDS.
05 WS-TOTAL-DISC-RATE PIC S9V99 COMP-3.
05 WS-TOTAL-DISC-AMT PIC S9(5)V99 COMP-3.
05 WS-TOTAL-SURCH-RATE PIC S9V99 COMP-3.
05 WS-TOTAL-SURCH-AMT PIC S9(5)V99 COMP-3.
05 WS-DISC-COUNT PIC 9(02).
05 WS-SURCH-COUNT PIC 9(02).
01 WS-FINAL-FIELDS.
05 WS-AFTER-SURCH PIC S9(5)V99 COMP-3.
05 WS-AFTER-DISC PIC S9(5)V99 COMP-3.
05 WS-FINAL-PREMIUM PIC S9(5)V99 COMP-3.
*----------------------------------------------------------------*
* TABLE SEARCH INDEX *
*----------------------------------------------------------------*
01 WS-IDX PIC 9(02).
01 WS-FACTOR-FOUND PIC X(01) VALUE 'N'.
88 FACTOR-FOUND VALUE 'Y'.
88 FACTOR-NOT-FOUND VALUE 'N'.
*----------------------------------------------------------------*
* COUNTERS *
*----------------------------------------------------------------*
01 WS-POLICIES-RATED PIC 9(05) VALUE ZEROS.
*----------------------------------------------------------------*
* REPORT LINES *
*----------------------------------------------------------------*
01 WS-RPT-TITLE.
05 FILLER PIC X(01) VALUE SPACE.
05 FILLER PIC X(70)
VALUE 'MIDWEST MUTUAL INSURANCE COMPANY - '
'AUTO PREMIUM RATING WORKSHEET'.
05 FILLER PIC X(61) VALUE SPACES.
01 WS-RPT-SEPARATOR.
05 FILLER PIC X(132) VALUE ALL '='.
01 WS-RPT-POLICY-HDR.
05 FILLER PIC X(01) VALUE SPACE.
05 FILLER PIC X(16) VALUE 'POLICY NUMBER: '.
05 WPH-POLICY-NUM PIC X(10).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(10) VALUE 'INSURED: '.
05 WPH-INSURED PIC X(25).
05 FILLER PIC X(65) VALUE SPACES.
01 WS-RPT-DRIVER-INFO.
05 FILLER PIC X(01) VALUE SPACE.
05 FILLER PIC X(14) VALUE 'DRIVER AGE: '.
05 WDI-AGE PIC ZZ9.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(16) VALUE 'VEHICLE CLASS: '.
05 WDI-VEH-CLASS PIC X(02).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(13) VALUE 'DRV POINTS: '.
05 WDI-POINTS PIC Z9.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(14) VALUE 'TERRITORY: '.
05 WDI-TERRITORY PIC X(02).
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(11) VALUE 'COVERAGE: '.
05 WDI-COVERAGE PIC X(05).
05 FILLER PIC X(21) VALUE SPACES.
01 WS-RPT-BLANK PIC X(132) VALUE SPACES.
01 WS-RPT-FACTOR-HDR.
05 FILLER PIC X(01) VALUE SPACE.
05 FILLER PIC X(40)
VALUE ' RATING COMPONENT'.
05 FILLER PIC X(15)
VALUE ' FACTOR '.
05 FILLER PIC X(20)
VALUE ' AMOUNT '.
05 FILLER PIC X(56) VALUE SPACES.
01 WS-RPT-FACTOR-DASH.
05 FILLER PIC X(01) VALUE SPACE.
05 FILLER PIC X(40) VALUE ALL '-'.
05 FILLER PIC X(15) VALUE ALL '-'.
05 FILLER PIC X(20) VALUE ALL '-'.
05 FILLER PIC X(56) VALUE SPACES.
01 WS-RPT-FACTOR-LINE.
05 FILLER PIC X(01) VALUE SPACE.
05 WFL-DESCRIPTION PIC X(38).
05 FILLER PIC X(02) VALUE SPACES.
05 WFL-FACTOR PIC Z9.9999.
05 FILLER PIC X(05) VALUE SPACES.
05 FILLER PIC X(02) VALUE '$ '.
05 WFL-AMOUNT PIC ZZ,ZZ9.99.
05 FILLER PIC X(58) VALUE SPACES.
01 WS-RPT-TOTAL-LINE.
05 FILLER PIC X(01) VALUE SPACE.
05 WTL-DESCRIPTION PIC X(38).
05 FILLER PIC X(18) VALUE SPACES.
05 FILLER PIC X(02) VALUE '$ '.
05 WTL-AMOUNT PIC ZZ,ZZ9.99.
05 FILLER PIC X(58) VALUE SPACES.
01 WS-RPT-DISC-LINE.
05 FILLER PIC X(01) VALUE SPACE.
05 WDL-DESCRIPTION PIC X(38).
05 FILLER PIC X(02) VALUE SPACES.
05 WDL-RATE PIC Z9.99.
05 FILLER PIC X(01) VALUE '%'.
05 FILLER PIC X(06) VALUE SPACES.
05 WDL-SIGN PIC X(01).
05 FILLER PIC X(01) VALUE '$'.
05 WDL-AMOUNT PIC ZZ,ZZ9.99.
05 FILLER PIC X(58) VALUE SPACES.
PROCEDURE DIVISION.
*================================================================*
* MAIN CONTROL *
*================================================================*
0000-MAIN-CONTROL.
PERFORM 1000-INITIALIZE
PERFORM 2000-RATE-POLICY
UNTIL END-OF-FILE
PERFORM 9000-FINALIZE
STOP RUN
.
*================================================================*
* INITIALIZE - OPEN FILES *
*================================================================*
1000-INITIALIZE.
OPEN INPUT POLICY-INPUT
OPEN OUTPUT RATING-REPORT
IF WS-INPUT-STATUS NOT = '00'
DISPLAY 'ERROR OPENING INPUT: ' WS-INPUT-STATUS
SET END-OF-FILE TO TRUE
END-IF
* Write report title
WRITE REPORT-LINE FROM WS-RPT-TITLE
WRITE REPORT-LINE FROM WS-RPT-SEPARATOR
PERFORM 8000-READ-INPUT
.
*================================================================*
* RATE ONE POLICY *
*================================================================*
2000-RATE-POLICY.
ADD 1 TO WS-POLICIES-RATED
* Step 1: Look up all rating factors
PERFORM 3000-LOOKUP-FACTORS
* Step 2: Calculate coverage premiums
PERFORM 4000-CALC-COVERAGE-PREMIUMS
* Step 3: Apply discounts and surcharges
PERFORM 5000-APPLY-DISC-SURCH
* Step 4: Apply premium bounds
PERFORM 6000-APPLY-BOUNDS
* Step 5: Write rating worksheet
PERFORM 7000-WRITE-WORKSHEET
PERFORM 8000-READ-INPUT
.
*================================================================*
* LOOK UP ALL RATING FACTORS FROM TABLES *
*================================================================*
3000-LOOKUP-FACTORS.
* Initialize all factors to 1.00 (neutral)
MOVE 1.00 TO WS-FOUND-AGE-FAC
MOVE 1.00 TO WS-FOUND-VEH-FAC
MOVE 1.00 TO WS-FOUND-DRV-FAC
MOVE 1.00 TO WS-FOUND-TERR-FAC
MOVE 1.00 TO WS-FOUND-LIAB-FAC
MOVE 1.00 TO WS-FOUND-COLL-FAC
MOVE 1.00 TO WS-FOUND-COMP-FAC
* Look up driver age factor
PERFORM 3100-LOOKUP-AGE
* Look up vehicle classification factor
PERFORM 3200-LOOKUP-VEHICLE
* Look up driving record factor
PERFORM 3300-LOOKUP-DRIVING-RECORD
* Look up territory factor
PERFORM 3400-LOOKUP-TERRITORY
* Look up coverage level factors
PERFORM 3500-LOOKUP-COVERAGE
.
*================================================================*
* LOOK UP DRIVER AGE FACTOR *
*================================================================*
3100-LOOKUP-AGE.
SET FACTOR-NOT-FOUND TO TRUE
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-AGE-TABLE-SIZE
OR FACTOR-FOUND
IF PI-DRIVER-AGE >= WS-AGE-MIN(WS-IDX)
AND PI-DRIVER-AGE <= WS-AGE-MAX(WS-IDX)
MOVE WS-AGE-FACTOR(WS-IDX)
TO WS-FOUND-AGE-FAC
SET FACTOR-FOUND TO TRUE
END-IF
END-PERFORM
IF FACTOR-NOT-FOUND
DISPLAY 'WARNING: NO AGE FACTOR FOR AGE '
PI-DRIVER-AGE ' - USING 1.00'
END-IF
.
*================================================================*
* LOOK UP VEHICLE CLASSIFICATION FACTOR *
*================================================================*
3200-LOOKUP-VEHICLE.
SET FACTOR-NOT-FOUND TO TRUE
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-VEH-TABLE-SIZE
OR FACTOR-FOUND
IF PI-VEHICLE-CLASS = WS-VEH-CODE(WS-IDX)
MOVE WS-VEH-FACTOR(WS-IDX)
TO WS-FOUND-VEH-FAC
SET FACTOR-FOUND TO TRUE
END-IF
END-PERFORM
IF FACTOR-NOT-FOUND
DISPLAY 'WARNING: NO VEHICLE FACTOR FOR '
PI-VEHICLE-CLASS ' - USING 1.00'
END-IF
.
*================================================================*
* LOOK UP DRIVING RECORD FACTOR *
*================================================================*
3300-LOOKUP-DRIVING-RECORD.
SET FACTOR-NOT-FOUND TO TRUE
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-DRV-TABLE-SIZE
OR FACTOR-FOUND
IF PI-DRIVING-POINTS >= WS-DRV-PTS-MIN(WS-IDX)
AND PI-DRIVING-POINTS <=
WS-DRV-PTS-MAX(WS-IDX)
MOVE WS-DRV-FACTOR(WS-IDX)
TO WS-FOUND-DRV-FAC
SET FACTOR-FOUND TO TRUE
END-IF
END-PERFORM
IF FACTOR-NOT-FOUND
DISPLAY 'WARNING: NO DRV FACTOR FOR POINTS '
PI-DRIVING-POINTS ' - USING 1.00'
END-IF
.
*================================================================*
* LOOK UP TERRITORY FACTOR *
*================================================================*
3400-LOOKUP-TERRITORY.
SET FACTOR-NOT-FOUND TO TRUE
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-TERR-TABLE-SIZE
OR FACTOR-FOUND
IF PI-TERRITORY = WS-TERR-CODE(WS-IDX)
MOVE WS-TERR-FACTOR(WS-IDX)
TO WS-FOUND-TERR-FAC
SET FACTOR-FOUND TO TRUE
END-IF
END-PERFORM
IF FACTOR-NOT-FOUND
DISPLAY 'WARNING: NO TERRITORY FACTOR FOR '
PI-TERRITORY ' - USING 1.00'
END-IF
.
*================================================================*
* LOOK UP COVERAGE LEVEL FACTORS *
*================================================================*
3500-LOOKUP-COVERAGE.
SET FACTOR-NOT-FOUND TO TRUE
PERFORM VARYING WS-IDX FROM 1 BY 1
UNTIL WS-IDX > WS-COV-TABLE-SIZE
OR FACTOR-FOUND
IF PI-COVERAGE-LEVEL = WS-COV-CODE(WS-IDX)
MOVE WS-COV-LIAB-FAC(WS-IDX)
TO WS-FOUND-LIAB-FAC
MOVE WS-COV-COLL-FAC(WS-IDX)
TO WS-FOUND-COLL-FAC
MOVE WS-COV-COMP-FAC(WS-IDX)
TO WS-FOUND-COMP-FAC
SET FACTOR-FOUND TO TRUE
END-IF
END-PERFORM
IF FACTOR-NOT-FOUND
DISPLAY 'WARNING: NO COVERAGE FACTOR FOR '
PI-COVERAGE-LEVEL ' - USING 1.00'
END-IF
.
*================================================================*
* CALCULATE PREMIUMS FOR EACH COVERAGE LINE *
* *
* Each coverage line premium = *
* Base Rate * Age Factor * Vehicle Factor * Driving Factor *
* * Territory Factor * Coverage Level Factor *
*================================================================*
4000-CALC-COVERAGE-PREMIUMS.
* Liability premium
COMPUTE WS-LIAB-PREMIUM ROUNDED =
WS-BASE-LIABILITY
* WS-FOUND-AGE-FAC
* WS-FOUND-VEH-FAC
* WS-FOUND-DRV-FAC
* WS-FOUND-TERR-FAC
* WS-FOUND-LIAB-FAC
ON SIZE ERROR
DISPLAY 'SIZE ERROR: LIABILITY CALC'
MOVE WS-MAX-PREMIUM TO WS-LIAB-PREMIUM
END-COMPUTE
* Collision premium
* BASIC coverage has no collision (factor = 0.00)
IF WS-FOUND-COLL-FAC > ZEROS
COMPUTE WS-COLL-PREMIUM ROUNDED =
WS-BASE-COLLISION
* WS-FOUND-AGE-FAC
* WS-FOUND-VEH-FAC
* WS-FOUND-DRV-FAC
* WS-FOUND-TERR-FAC
* WS-FOUND-COLL-FAC
ON SIZE ERROR
DISPLAY 'SIZE ERROR: COLLISION CALC'
MOVE WS-MAX-PREMIUM
TO WS-COLL-PREMIUM
END-COMPUTE
ELSE
MOVE ZEROS TO WS-COLL-PREMIUM
END-IF
* Comprehensive premium
* BASIC coverage has no comprehensive (factor = 0.00)
IF WS-FOUND-COMP-FAC > ZEROS
COMPUTE WS-COMP-PREMIUM ROUNDED =
WS-BASE-COMPREHENSIVE
* WS-FOUND-AGE-FAC
* WS-FOUND-VEH-FAC
* WS-FOUND-DRV-FAC
* WS-FOUND-TERR-FAC
* WS-FOUND-COMP-FAC
ON SIZE ERROR
DISPLAY 'SIZE ERROR: COMP CALC'
MOVE WS-MAX-PREMIUM
TO WS-COMP-PREMIUM
END-COMPUTE
ELSE
MOVE ZEROS TO WS-COMP-PREMIUM
END-IF
* Calculate subtotal
COMPUTE WS-SUBTOTAL-PREMIUM =
WS-LIAB-PREMIUM + WS-COLL-PREMIUM
+ WS-COMP-PREMIUM
.
*================================================================*
* APPLY DISCOUNTS AND SURCHARGES *
* *
* Surcharges are applied first (multiplicative on subtotal), *
* then discounts are applied (multiplicative on post-surcharge). *
* This order ensures surcharges are not reduced by discounts. *
*================================================================*
5000-APPLY-DISC-SURCH.
* Calculate surcharges
MOVE ZEROS TO WS-TOTAL-SURCH-RATE
MOVE ZEROS TO WS-SURCH-COUNT
IF PI-AT-FAULT-CLAIMS > 0
COMPUTE WS-TOTAL-SURCH-RATE =
WS-TOTAL-SURCH-RATE +
(WS-AT-FAULT-SURCH * PI-AT-FAULT-CLAIMS)
ADD PI-AT-FAULT-CLAIMS TO WS-SURCH-COUNT
END-IF
IF PI-MOVING-VIOLATIONS > 0
COMPUTE WS-TOTAL-SURCH-RATE =
WS-TOTAL-SURCH-RATE +
(WS-VIOLATION-SURCH * PI-MOVING-VIOLATIONS)
ADD PI-MOVING-VIOLATIONS TO WS-SURCH-COUNT
END-IF
* Apply surcharges
COMPUTE WS-TOTAL-SURCH-AMT ROUNDED =
WS-SUBTOTAL-PREMIUM * WS-TOTAL-SURCH-RATE
COMPUTE WS-AFTER-SURCH =
WS-SUBTOTAL-PREMIUM + WS-TOTAL-SURCH-AMT
* Calculate discounts
MOVE ZEROS TO WS-TOTAL-DISC-RATE
MOVE ZEROS TO WS-DISC-COUNT
IF PI-MULTI-CAR
ADD WS-MULTI-CAR-DISC TO WS-TOTAL-DISC-RATE
ADD 1 TO WS-DISC-COUNT
END-IF
IF PI-GOOD-STUDENT
ADD WS-GOOD-STUDENT-DISC TO WS-TOTAL-DISC-RATE
ADD 1 TO WS-DISC-COUNT
END-IF
IF PI-DEFENSIVE-DRV
ADD WS-DEFENSIVE-DRV-DISC TO WS-TOTAL-DISC-RATE
ADD 1 TO WS-DISC-COUNT
END-IF
* Apply discounts to the post-surcharge amount
COMPUTE WS-TOTAL-DISC-AMT ROUNDED =
WS-AFTER-SURCH * WS-TOTAL-DISC-RATE
COMPUTE WS-AFTER-DISC =
WS-AFTER-SURCH - WS-TOTAL-DISC-AMT
MOVE WS-AFTER-DISC TO WS-FINAL-PREMIUM
.
*================================================================*
* APPLY MINIMUM AND MAXIMUM PREMIUM BOUNDS *
*================================================================*
6000-APPLY-BOUNDS.
IF WS-FINAL-PREMIUM < WS-MIN-PREMIUM
MOVE WS-MIN-PREMIUM TO WS-FINAL-PREMIUM
END-IF
IF WS-FINAL-PREMIUM > WS-MAX-PREMIUM
MOVE WS-MAX-PREMIUM TO WS-FINAL-PREMIUM
END-IF
.
*================================================================*
* WRITE COMPLETE RATING WORKSHEET TO REPORT *
*================================================================*
7000-WRITE-WORKSHEET.
WRITE REPORT-LINE FROM WS-RPT-BLANK
* Policy header
MOVE PI-POLICY-NUMBER TO WPH-POLICY-NUM
MOVE PI-INSURED-NAME TO WPH-INSURED
WRITE REPORT-LINE FROM WS-RPT-POLICY-HDR
* Driver/vehicle information
MOVE PI-DRIVER-AGE TO WDI-AGE
MOVE PI-VEHICLE-CLASS TO WDI-VEH-CLASS
MOVE PI-DRIVING-POINTS TO WDI-POINTS
MOVE PI-TERRITORY TO WDI-TERRITORY
MOVE PI-COVERAGE-LEVEL TO WDI-COVERAGE
WRITE REPORT-LINE FROM WS-RPT-DRIVER-INFO
WRITE REPORT-LINE FROM WS-RPT-BLANK
* Rating factor header
WRITE REPORT-LINE FROM WS-RPT-FACTOR-HDR
WRITE REPORT-LINE FROM WS-RPT-FACTOR-DASH
* Liability line
MOVE 'LIABILITY BASE RATE' TO WFL-DESCRIPTION
MOVE 1.0000 TO WFL-FACTOR
MOVE WS-BASE-LIABILITY TO WFL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
* Display each factor
PERFORM 7100-WRITE-FACTOR-LINES
* Liability premium
MOVE 'RATED LIABILITY PREMIUM'
TO WTL-DESCRIPTION
MOVE WS-LIAB-PREMIUM TO WTL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-TOTAL-LINE
* Collision premium
IF WS-COLL-PREMIUM > ZEROS
MOVE 'RATED COLLISION PREMIUM'
TO WTL-DESCRIPTION
MOVE WS-COLL-PREMIUM TO WTL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-TOTAL-LINE
END-IF
* Comprehensive premium
IF WS-COMP-PREMIUM > ZEROS
MOVE 'RATED COMPREHENSIVE PREMIUM'
TO WTL-DESCRIPTION
MOVE WS-COMP-PREMIUM TO WTL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-TOTAL-LINE
END-IF
* Subtotal
WRITE REPORT-LINE FROM WS-RPT-FACTOR-DASH
MOVE 'SUBTOTAL BEFORE DISC/SURCH'
TO WTL-DESCRIPTION
MOVE WS-SUBTOTAL-PREMIUM TO WTL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-TOTAL-LINE
* Surcharges
IF WS-TOTAL-SURCH-AMT > ZEROS
MOVE 'SURCHARGES' TO WDL-DESCRIPTION
COMPUTE WDL-RATE =
WS-TOTAL-SURCH-RATE * 100
MOVE '+' TO WDL-SIGN
MOVE WS-TOTAL-SURCH-AMT TO WDL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-DISC-LINE
END-IF
* Discounts
IF WS-TOTAL-DISC-AMT > ZEROS
MOVE 'DISCOUNTS' TO WDL-DESCRIPTION
COMPUTE WDL-RATE =
WS-TOTAL-DISC-RATE * 100
MOVE '-' TO WDL-SIGN
MOVE WS-TOTAL-DISC-AMT TO WDL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-DISC-LINE
END-IF
* Final premium
WRITE REPORT-LINE FROM WS-RPT-FACTOR-DASH
MOVE 'FINAL ANNUAL PREMIUM' TO WTL-DESCRIPTION
MOVE WS-FINAL-PREMIUM TO WTL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-TOTAL-LINE
WRITE REPORT-LINE FROM WS-RPT-SEPARATOR
.
*================================================================*
* WRITE INDIVIDUAL FACTOR LINES FOR THE WORKSHEET *
*================================================================*
7100-WRITE-FACTOR-LINES.
MOVE ' DRIVER AGE FACTOR' TO WFL-DESCRIPTION
MOVE WS-FOUND-AGE-FAC TO WFL-FACTOR
MOVE ZEROS TO WFL-AMOUNT
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
MOVE ' VEHICLE CLASS FACTOR' TO WFL-DESCRIPTION
MOVE WS-FOUND-VEH-FAC TO WFL-FACTOR
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
MOVE ' DRIVING RECORD FACTOR'
TO WFL-DESCRIPTION
MOVE WS-FOUND-DRV-FAC TO WFL-FACTOR
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
MOVE ' TERRITORY FACTOR' TO WFL-DESCRIPTION
MOVE WS-FOUND-TERR-FAC TO WFL-FACTOR
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
MOVE ' COVERAGE LEVEL FACTOR'
TO WFL-DESCRIPTION
MOVE WS-FOUND-LIAB-FAC TO WFL-FACTOR
WRITE REPORT-LINE FROM WS-RPT-FACTOR-LINE
.
*================================================================*
* READ NEXT POLICY INPUT RECORD *
*================================================================*
8000-READ-INPUT.
READ POLICY-INPUT
AT END
SET END-OF-FILE TO TRUE
END-READ
.
*================================================================*
* FINALIZE AND CLOSE FILES *
*================================================================*
9000-FINALIZE.
CLOSE POLICY-INPUT
RATING-REPORT
DISPLAY 'AUTO RATING COMPLETE'
DISPLAY ' POLICIES RATED: ' WS-POLICIES-RATED
.
The JCL to execute the rating engine follows:
//AUTORATE JOB (ACCT),'AUTO RATING',CLASS=A,
// MSGCLASS=X,NOTIFY=&SYSUID
//*
//*================================================================*
//* AUTO INSURANCE PREMIUM RATING ENGINE *
//*================================================================*
//*
//STEP01 EXEC PGM=AUTORATE
//STEPLIB DD DSN=MMIC.RATING.LOADLIB,DISP=SHR
//POLYIN DD DSN=MMIC.POLICY.INPUT,DISP=SHR
//RATEOUT DD DSN=MMIC.RATING.WORKSHEET,DISP=(NEW,CATLG,DELETE),
// SPACE=(CYL,(5,2),RLSE),
// DCB=(RECFM=FB,LRECL=132,BLKSIZE=0)
//SYSOUT DD SYSOUT=*
How the Program Works
Table-Driven Architecture
The program's most important design characteristic is its separation of data from logic. Every rate and factor is stored in tables defined in WORKING-STORAGE using VALUE clauses and REDEFINES. In a production system, these tables would be loaded from external VSAM or sequential files during initialization. When actuaries file new rates with the state insurance department and receive regulatory approval, they update the rate files. The program itself never changes.
Each table uses a consistent structure: a raw data area initialized with VALUE clauses, and a REDEFINES that imposes a structured table layout with OCCURS. This pattern is the COBOL equivalent of a configuration file or database-driven approach in modern systems.
Factor Lookup Pattern
Every factor lookup follows the same pattern: iterate through the table entries using PERFORM VARYING until a match is found or the table is exhausted. Range-based lookups (like driver age) compare the input value to minimum and maximum values. Exact-match lookups (like vehicle class or territory) compare the input to a code value. If no match is found, a default factor of 1.00 is used and a warning is displayed.
This pattern is reused across five lookup paragraphs (3100 through 3500), demonstrating the modular design that makes insurance rating engines maintainable. Adding a new rating factor requires adding one new table, one new lookup paragraph, and one additional multiplication in the coverage calculation.
Multi-Factor Premium Calculation
The premium for each coverage line is the product of the base rate and all applicable factors:
Premium = Base * Age * Vehicle * Driving * Territory * Coverage
This multiplicative approach means that risk factors compound: a young driver (factor 2.15) of a sports car (factor 1.40) in an urban territory (factor 1.35) pays approximately 4.06 times the base rate before coverage level adjustments. The use of ROUNDED on every COMPUTE ensures that each intermediate result is rounded to the nearest cent.
Discount and Surcharge Application
Surcharges are applied before discounts, which is a standard insurance practice. This prevents discounts from reducing the penalty for adverse driving history. The surcharge is calculated as a percentage of the base premium, then added. The discount is then calculated as a percentage of the post-surcharge amount, then subtracted. Both use COMP-3 arithmetic with ROUNDED.
Discussion Questions
-
Why does the program initialize all factors to 1.00 before performing table lookups? What would happen if a factor field contained zero and no match was found in the table?
-
The program applies surcharges before discounts. What financial impact would reversing this order have? Why do insurance regulators typically require surcharges to be applied first?
-
In production, the rating tables would be loaded from external files rather than VALUE clauses. What are the advantages of this approach? What validation should be performed when loading external rate tables?
-
The program uses PERFORM VARYING for table lookups. How would using SEARCH ALL (binary search) improve performance, and what prerequisite condition would the tables need to meet?
-
Consider adding a new rating factor for "years of continuous coverage" (loyalty discount). What changes would be needed to the data structures, lookup logic, and premium calculation? How does the table-driven architecture minimize the code changes required?
Connection to Chapter Concepts
This case study directly applies these Chapter 35 concepts:
- Table-driven rate calculation: All rates and factors stored in COBOL tables, separating data from logic (Section 35.2).
- Multi-factor premium computation: Multiplicative application of independent risk factors (Section 35.2).
- EVALUATE for code-to-value mapping: Though this program uses PERFORM VARYING for lookups, the EVALUATE pattern is discussed for simpler mappings (Section 35.1).
- 88-level condition names: Used for input flags like multi-car and good-student indicators (Section 35.1).
- COMP-3 for all monetary calculations: Base rates, factors, and premiums all use packed decimal (Section 35.2).
- ROUNDED and ON SIZE ERROR: Applied to every premium calculation (Section 35.2).
- Regulatory compliance: The rating worksheet provides the audit trail required by state insurance regulators (Section 35.5).
- Modular paragraph design: Each factor lookup is a separate paragraph, promoting maintainability (Section 35.3).