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:

  1. 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.

  2. Multiple coverage lines: Rate three coverage lines separately -- liability, collision, and comprehensive -- each with its own base rate and applicable factors.

  3. Discount and surcharge application: After the base calculation, apply eligible discounts (multi-car, good student, defensive driving) and surcharges (at-fault accident, moving violation).

  4. Premium bounds checking: Ensure the calculated premium does not fall below a minimum premium floor or exceed a regulatory maximum.

  5. 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

  1. 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?

  2. 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?

  3. 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?

  4. 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?

  5. 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).