Rating Plugin
This page describes instructions for using the new JavaScript-based rating engine for Socotra, which supersedes the Liquid-based rating system.
Note
This topic does not apply to rating for Premium Reports. Those continue to use Liquid rating.
The plugin will rate all perils for a policy transaction at one time. This allows doing calculations that are common across perils one time, and also makes it easier to manage situations where there are interdependencies between perils, such as in “minimum total premium” scenarios.
The basic approach is that a set of peril characteristics objects each need to be rated. The identities of those characteristics are passed by locator in the policyExposurePerils
property of the data object, and each can be correlated with actual objects that are found in the policy
property, which contains a full PolicyResponse object.
Each ratable peril characteristic must be rated with a RatingPluginPriceResponse object in the return object.
Enabling the Plugin
To enable the rating plugin for a product, in that product’s policy.json
file, add a getPerilRates
property to the plugin enablement section. For example:
{
"plugins": {
"getPerilRates": {
"path": "main/rater.js",
"enabled": true
}
}
}
Rating Calculations
Rating is done on a “per-peril” basis, where each segment of each peril is priced independently. There are three options for how the pricing calculation is done:
Specify the premium rate and let Socotra compute the actual price by multiplying by the duration of the segment; or
Specify the actual premium for the segment and let Socotra infer the rate; or
Specify both the actual premium and the rate
See Premium Calculations for details about premium and commission values and their exact-
analogues.
Data Object
The following data
object is passed to the plugin for use by the plugin code:
requiredoperation string new_business | endorsement | renewal | reinstatementpolicy PolicyResponsepolicyExposurePerils [RatingPluginCharacteristics]tenantTimeZone stringoptionalendorsementLocator stringnewPaymentScheduleName stringquoteLocator stringreinstatementLocator stringrenewalLocator string
requiredpolicyCharacteristicsLocator stringexposureCharacteristicsLocator stringperilCharacteristicsLocator string
Return Object
The object returned from the plugin should take the following form:
requiredpricedPerilCharacteristics map<string,RatingPluginPriceResponse>optionalexceptionMessage string
The pricedPerilCharacteristics
property is a map of the peril characteristics locators that are being priced to the specific pricing information:
optionalcommissions [RatingPluginCommissionsResponse]exactPremium stringexactTechnicalPremium stringyearlyPremium stringyearlyTechnicalPremium string
requiredrecipient stringoptionalexactAmount stringyearlyAmount string
Validation
The response from the plugin must conform to the following criteria:
The keys in the return object’s
pricedPerilCharacteristics
map must correspond 1:1 with eachperilCharacteristicsLocator
in the input’spolicyExposurePerils
.No priced characteristics other than those specified in the request should be returned.
Script Example: Calculating by Rate
The following implementation of rater.js
illustrates a simplified rating algorithm:
function getPerilRates(data)
{
let policy = data.policy;
// This is the return object that we'll decorate with rating calculations
let ret = { pricedPerilCharacteristics: {} };
// For each peril characteristics object, look at its peril to get a rating
// factor and then multiply by vehicle value to get the premium.
for (const pep of data.policyExposurePerils)
{
let peril = getPerilFromPerilCharacteristicsLocator(policy, pep);
let exposureCharacteristics = getExposureCharacteristicsFromExposureCharacteristicsLocator(policy, pep);
let vehicleValue = parseFloat(exposureCharacteristics.fieldValues.vehicle_value[0]);
let ratingFactor;
switch (peril.name)
{
case "bodily_injury": ratingFactor = 52.0; break;
case "collision": ratingFactor = 45.5; break;
case "comprehensive": ratingFactor = 32.5; break;
default: ratingFactor = 12.0; break;
}
let yearlyPremium = round2(vehicleValue * ratingFactor / 1000);
ret.pricedPerilCharacteristics[pep.perilCharacteristicsLocator] = {
yearlyPremium: yearlyPremium,
yearlyTechnicalPremium: round2(yearlyPremium * 0.8),
commissions:[
{
yearlyAmount: round2(yearlyPremium * 0.1),
recipient: "broker_abc" // a code that specifies who gets the commission
}
]
}
}
return ret;
}
function getPerilFromPerilCharacteristicsLocator(policy, pep)
{
for (exp of policy.exposures)
for (peril of exp.perils)
if (peril.characteristics.some(c => c.locator == pep.perilCharacteristicsLocator))
return peril;
throw `Peril characteristics ${pep.perilCharacteristicsLocator} not found!`;
}
function getExposureCharacteristicsFromExposureCharacteristicsLocator(policy, pep)
{
for (exp of policy.exposures)
if (exp.characteristics.some(c => c.locator == pep.exposureCharacteristicsLocator))
return exp.characteristics.find(c => c.locator == pep.exposureCharacteristicsLocator);
throw `ExposureCharacteristics ${pep.exposureCharacteristicsLocator} not found!`;
}
function round2(amount)
{
return Math.round(amount * 100.0) / 100.0;
}
exports.getPerilRates = getPerilRates;