A per-class-code workers' compensation model with a state load and experience modification.
Workers' compensation covers employees' medical costs and lost wages after a work injury. In the US it is rated on payroll by class code, with each class reflecting the hazard of the work, and an experience modification for the employer's own loss record.
A child model calculates the manual premium for each class code from its payroll. The parent model sums the manual premiums, then applies a state load and the employer's experience modification, plus a policy fee.
Policies with no class codes or very small payrolls are declined. High experience modifications and very large payrolls are referred.
Three further factors adjust the premium: a certified safety programme, a return to work programme and the number of recent claims.
| Field | Label | Type | Default | Allowed values |
|---|---|---|---|---|
state | State | string | CA | CA, NY, TX, FL, IL |
experience_mod | Experience modification factor | decimal | 1 | 0.8, 1, 1.25, 1.5 |
class_codes | Class codes | array | list | A list of items, each rated by the child model |
safety_program | Certified safety programme | boolean | false | false, true |
return_to_work | Return to work programme | boolean | false | false, true |
claims_count_3y | Claims in the last 3 years | integer | 0 | 0, 1, 3, 6 |
Steps run in order. Each one can use the inputs and the outputs of every step before it.
Overall state loading applied to the manual premium (proxy for state assessment differences).
{
"id": "state_load_rates",
"key": "state_load_rates",
"step": "collection",
"name": "State load factor",
"retain": true,
"collection": [
["state", "state_load"],
["CA", 1.15],
["NY", 1.12],
["TX", 1],
["FL", 1.05],
["IL", 1.08]
],
"format": {
"state_load": {
"key": "state_load",
"label": "State load factor",
"exp": "collection.filter(state=={{state}}).map(state_load).first()",
"type": "decimal",
"def": 1
}
}
}Iterate class_codes[]. Child model returns manual premium per class code; parent sums into manual premium total.
Prices a single class code = (rate per $100 payroll × payroll).
Class-code rate lookup. Rate per $100 of payroll by NCCI class code. Higher-hazard codes carry higher rates.
Manual premium. (Payroll / 100) × rate per $100.
{
"id": "per_class_rating",
"key": "per_class_rating",
"step": "modules",
"name": "Per-class-code rating",
"format": {
"manual_premium_total": {
"key": "manual_premium_total",
"label": "Manual premium total",
"exp": "collection.sum(result)",
"type": "decimal",
"def": 0
},
"total_payroll": {
"key": "total_payroll",
"label": "Total payroll",
"exp": "collection.sum(payroll)",
"type": "decimal",
"def": 0
},
"classes_count": {
"key": "classes_count",
"label": "Number of class codes",
"exp": "collection.count()",
"type": "integer",
"def": 0
}
},
"child_model_steps": [
{
"id": "code_rates",
"key": "code_rates",
"step": "collection",
"name": "Class-code rate lookup",
"retain": true,
"collection": [
["code", "code_rate_per_100"],
["8810", 0.25],
["8871", 0.18],
["5403", 4.8],
["9082", 2.4],
["9014", 3.1]
],
"format": {
"code_rate_per_100": {
"key": "code_rate_per_100",
"label": "Class code rate per $100",
"exp": "collection.filter(code=={{code}}).map(code_rate_per_100).first()",
"type": "decimal",
"def": 1
}
}
},
{
"id": "manual_premium",
"key": "manual_premium",
"step": "calculation",
"name": "Manual premium",
"def": 0,
"formula": "round(({{payroll}} / 100) * {{code_rate_per_100}}, 2)"
}
]
}A certified workplace safety programme reduces the frequency of injuries.
{
"id": "wc_safety_rates",
"key": "wc_safety_rates",
"step": "collection",
"name": "Safety programme factor",
"retain": true,
"collection": [
["safety_program_value", "wc_safety_factor_rel"],
[false, 1],
[true, 0.95]
],
"format": {
"wc_safety_factor": {
"key": "wc_safety_factor",
"label": "Safety programme factor",
"exp": "collection.filter(safety_program_value=={{safety_program}}).map(wc_safety_factor_rel).first()",
"type": "decimal",
"def": 1
}
}
}Getting injured employees back to suitable work quickly reduces lost wage costs.
{
"id": "rtw_rates",
"key": "rtw_rates",
"step": "collection",
"name": "Return to work factor",
"retain": true,
"collection": [
["return_to_work_value", "rtw_factor_rel"],
[false, 1],
[true, 0.97]
],
"format": {
"rtw_factor": {
"key": "rtw_factor",
"label": "Return to work factor",
"exp": "collection.filter(return_to_work_value=={{return_to_work}}).map(rtw_factor_rel).first()",
"type": "decimal",
"def": 1
}
}
}A high number of recent claims points to frequency problems the experience mod may not yet show.
{
"id": "wc_frequency_rates",
"key": "wc_frequency_rates",
"step": "collection",
"name": "Claims frequency factor",
"retain": true,
"collection": [
["claims_count_3y_min", "claims_count_3y_max", "wc_frequency_factor_rel"],
[0, 1, 1],
[2, 4, 1.08],
[5, 999, 1.2]
],
"format": {
"wc_frequency_factor": {
"key": "wc_frequency_factor",
"label": "Claims frequency factor",
"exp": "collection.filter(claims_count_3y_min<={{claims_count_3y}}).filter(claims_count_3y_max>={{claims_count_3y}}).map(wc_frequency_factor_rel).first()",
"type": "decimal",
"def": 1
}
}
}Manual premium × state load × experience mod, plus $250 policy fee. Multiplied by the safety programme factor, return to work factor, claims frequency factor.
{
"id": "policy_premium",
"key": "policy_premium",
"step": "calculation",
"name": "Policy premium",
"def": 0,
"formula": "round(({{manual_premium_total}} * {{state_load}} * {{experience_mod}} * {{wc_safety_factor}} * {{rtw_factor}} * {{wc_frequency_factor}}) + 250, 2)"
}Decline policies with no class codes or total payroll under $10k (below minimum earned premium threshold).
{
"id": "wc_exclusions",
"key": "wc_exclusions",
"step": "exclusion",
"name": "Workers comp exclusions",
"def": false,
"items": [
{
"id": "no_class_codes",
"name": "No class codes supplied",
"exp": "{{classes_count}} == 0",
"def": false
},
{
"id": "payroll_too_low",
"name": "Total payroll below $10k",
"exp": "{{total_payroll}} < 10000",
"def": false
}
]
}Refer high-experience-mod employers or very large payrolls to underwriter review.
{
"id": "wc_refers",
"key": "wc_refers",
"step": "refer",
"name": "Workers comp refers",
"def": false,
"items": [
{
"id": "high_mod",
"name": "Experience mod at or above 1.40",
"exp": "{{experience_mod}} >= 1.40",
"def": false
},
{
"id": "large_payroll",
"name": "Total payroll over $5m",
"exp": "{{total_payroll}} > 5000000",
"def": false
}
]
}This quote was priced by the Ptally rating engine. The trace below follows it through every step to the final result.
{
"state": "CA",
"experience_mod": 1,
"class_codes": [
{
"code": "8810",
"payroll": 300000
}
],
"safety_program": true,
"return_to_work": true,
"claims_count_3y": 3
}state_load = 1.15Item 1 {"code":"8810","payroll":300000} → 750manual_premium_total = 750 · total_payroll = 300,000 · classes_count = 1wc_safety_factor = 0.95rtw_factor = 0.97wc_frequency_factor = 1.08round((750 * 1.15 * 1 * 0.95 * 0.97 * 1.08) + 250, 2) = 1,108.38No class codes supplied: not firedTotal payroll below $10k: not firedExperience mod at or above 1.40: not firedTotal payroll over $5m: not firedSelect workers' compensation as the default model for a new project, then change the rates, rules and tests to match your product. Our consultants can do this for you, with no implementation fee.