# # Rating

Rating is performed by taking the details about a Risk Type (Fields, Items, Rate Tables, and Calculations) and details about a Quote (risks, field answers, chosen items) and combining them to determine each Item's premium, limits, and deductible.

## # Writing Calculations

Calculations are single-line statements that return a numeric result. They look like the following:

```
baseRate * rateFactorTable * seniorDiscount
```

This calculation says to take the `baseRate`

and multiply it by the `rateFactorTable`

and the `seniorDiscount`

.

### # Reference Names

Each Field, Item, Rate Table, and Calculation has a reference name. Calculations use this reference name to refer to the Fields, Items, Rate Tables, and Calculations. This allow information about these entities to change (like updating a label or default value) without affecting rating logic.

#### # Valid Reference Names

Reference names must be valid a Python identifier. This means they can only start with a letter or underscore and can only contain letters, numbers, and underscores.

The following are **valid** reference names:

`gender`

`medical_expense_baseRate_table`

`bodilyInjuryLimit`

`driver1`

`_id`

The following are **invalid** reference names:

`date-of-birth`

(contains hyphens)`$value`

(contains a dollar sign)`1stdriver`

(starts with a number)

#### # Reserved Reference Names

Some reference names are already reserved by BriteLines. These reference names are unavailable to be used by any Field, Rate Table, Calculation, or Item.

The following reference names are reserved by BriteLines along with other Python Built-ins:

`bc`

`Q`

### # Arithmetic Operations

The following arithmetic operations can be performed on references which return numbers (Fields of type Number, Rate Tables, and Calculations).

#### # Addition

The `+`

character is used to add numbers together.

```
baseRateTable + numberField + otherCalculation
```

#### # Subtraction

The `-`

is used to subtract one number from another number.

```
baseRateTable - numberField
```

#### # Multiplication

The `*`

character is used to multiply numbers together.

```
baseRateTable * rateTableFactor
```

#### # Division

The `/`

character is used to divide one number by another number.

```
baseRateTable / 2
```

### # Comparison Operations

Comparison operations compare values and return either true or false according to the condition.

#### # Greater than

True if left operand is greater than the right.

```
numOfDrivers > numOfVehicles
```

#### # Less than

True if left operand is less than the right.

```
numOfDrivers < numOfVehicles
```

#### # Equal to

True if both operands are equal.

```
numOfDrivers == numOfVehicles
```

#### # Not equal to

True if operands are not equal.

```
numOfDrivers != numOfVehicles
```

#### # Greater than or equal to

True if left operand is greater than or equal to the right.

```
numOfDrivers >= numOfVehicles
```

#### # Less than or equal to

True if left operand is less than or equal to the right.

```
numOfDrivers <= numOfVehicles
```

### # Scopes

Scopes determine which references are available to Calculation. Shared Calculations and Item Calculations have different scopes.

Shared Calculations have a scope that can reference all Fields, all Rate Tables, and other Shared Calculations. They cannot reference specific Item Calculations.

Item Calculations have a scope that can reference all Fields, all Rate Tables, all Shared Calculations, and the other Calculations for that Item.

Because of these rules Shared Calculation reference names must be unique across all Fields, Items, Rate Tables, and Calculations. Item Calculation reference names, however, only need to be unique across Fields, Items, Rate Tables, Shared Calculations, and the current Item's Calculations.

This means that Items `bodilyInjury`

and `comprehensive`

can both have Calculations called `baseRate`

and the names will not clash. You *couldn't* have a Shared Calculation called `baseRate`

, though. When rating the `bodilyInjury`

Item the Rating Engine wouldn't know if it should use the value from the Item's `baseRate`

Calculation or the Risk Type's `baseRate`

Shared Calculation.

### # Circular Reference Errors

Calculations must not reference each other. Imagine the following two Calculations:

`baseRate`

```
rateCalc * seniorDiscount
```

and...

`rateCalc`

```
baseRate * otherFactor
```

This would result in a Circular Reference Error because `baseRate`

refers to `rateCalc`

and `rateCalc`

refers to `baseRate`

. The rating engine would have no way of determining the value for either one.

### # Calculation Types

Calculations have the following types:

- Variable
- Premium
- Limit
- Deductible

Variable Calculations simply perform the calculation and store it in the reference name. The result can then be used by other Calculations. All Shared Calculations are Variable Calculations.

Premium, Limit, and Deductible Calculations result in the Item's premium, limit, and deductible respectively.

### # Available Variables

#### # `bc.policyInceptionDate`

The date in which the policy was first created.

```
bc.age(bc.policyInceptionDate)
```

If policy inception date is 2014-01-01 and rating date is 2017-01-01 then the above calculation will resolve to 3.

#### # `bc.transactionEffectiveDate`

The effective date of the current transaction.

```
bc.age(bc.transactionEffectiveDate)
```

#### # `bc.policyTermEffectiveDate`

The effective date of the current term.

```
bc.age(bc.policyTermEffectiveDate)
```

#### # `bc.isTransactionNewBusiness`

Returns `True`

if the current transaction type is New Business otherwise it will return `False`

.

```
2 if bc.isTransactionNewBusiness else 4
```

If the transaction type is New Business then the above calculation will return 2 otherwise it will return 4.

#### # `bc.isTransactionRenewal`

Returns `True`

if the current transaction type is Renewal otherwise it will return `False`

.

```
2 if bc.isTransactionRenewal else 4
```

If the transaction type is Renewal then the above calculation will return 2 otherwise it will return 4.

#### # `bc.isTransactionEndorsement`

Returns `True`

if the current transaction type is Endorsement otherwise it will return `False`

.

```
2 if bc.isTransactionEndorsement else 4
```

If the transaction type is Endorsement then the above calculation will return 2 otherwise it will return 4.

#### # `bc.isTransactionCancellation`

Returns `True`

if the current transaction type is Cancellation otherwise it will return `False`

.

```
2 if bc.isTransactionCancellation else 4
```

If the transaction type is Cancellation then the above calculation will return 2 otherwise it will return 4.

#### # `bc.isTransactionRewrite`

Returns `True`

if the current transaction type is Rewrite otherwise it will return `False`

.

```
2 if bc.isTransactionRewrite else 4
```

If the transaction type is Rewrite then the above calculation will return 2 otherwise it will return 4.

### # Available Functions

The rating engine provides several functions that can be used in your Calculations.

#### # `bc.optional`

This function marks Data Fields, Rate Tables, and Items as optional. If a Rate Table is marked as optional then BriteLines will determine which Fields that Rate Table uses as sources and also mark them as optional.

To use `bc.optional()`

, wrap Data Field, Rate Table, or Item reference names in the function.

##### # `bc.optional`

with Rate Tables

Example:

```
bc.min(primaryDriverRateTable, bc.optional(secondaryDriverRateTable))
```

By wrapping `secondaryDriverRateTable`

as `bc.optional`

, all of the data fields which `secondaryDriverRateTable`

points to
will be optional during quoting.

If `secondaryDriverRateTable`

has no default value set or you want to override the default value then you can pass a default value to `bc.optional`

function. The default value must be a number.

```
bc.min(primaryDriverRateTable, bc.optional(secondaryDriverRateTable, default=1))
```

##### # `bc.optional`

with Items

Example:

```
mandatoryItem.premium.term.value + bc.optional(optionalItem.premium.term.value, default=0)
```

In this example, we add a mandatory Item's premium to an optional Item's premium.

If the mandatory Item's premium is

**50**, and the optional Item exists on the policy and has a premium of**50**, then this Calculation will return**100**.If the mandatory Item's premium is

**50**, and the optional Item has not been enabled for the policy, then this Calculation will return**50**.If the mandatory Item's premium is

**50**, and the optional Item exists on the policy but cannot be resolved yet, then this Calculation will return**50**.

##### # Optional Fields in Quoting

During quoting, a Field will only be considered optional if:

- All Calculations that refer directly to the Field are wrapped in
`bc.optional()`

. - All Rate Tables that refer to the Field are wrapped in
`bc.optional()`

.

This means that a Field can be optional or required depending on the Items that are selected for a Risk. For example:

- We have a Quote with Item 1 enabled. All Item 1 Calculations mark the
`additionalDriver`

Field as optional. It is optional on the Quote. - Next, Item 2 is enabled on the Quote. It has Calculations that refer to
`additionalDriver`

which are**not**wrapped in`bc.optional()`

. Additional Driver is now a required Field (because it is not filled out then Item 2 could not rate).

#### # `bc.age`

Returns the age of something in years from a given date or number.

```
bc.age(dateOfBirth)
```

This allows us to always collect the date of origin and find it's age dynamically.
So we can collect Birthday/Year Built/Year Purchased, and `bc.age()`

will always
use the Quote's rating date to find the age based on these dates.

For example, if you were to collect `dateOfBirth`

as a date input, and the user chooses
"01/31/1992", and the rating date year is 2017, then `bc.age(dateOfBirth)`

will return 25.

This function is not simply the difference in years, but accounts for aging
in the current year as well. So if the rating date is "12/13/2017" and the user puts in
"12/15/2000", then the value is *not* 17, but 16 because the 15th has not yet passed.

Users can also pass in numbers, in which case `bc.age()`

will assume the number is a year.
For instance, a calculation of `bc.age(2010)`

will return 8 if the current year is 2018. This is useful for calculating the age of vehicles:

```
bc.age(vehicleModelYear)
```

`bc.age()`

will always return the difference between the rating date and the value passed into the function. This means `bc.age()`

may return a negative number for dates or years that are in the future. To ensure that no values lower than 0 are returned, change your calculation to:

```
bc.max(bc.age(vehicleModelYear), 0)`
```

#### # `bc.condition`

Returns different results based on whether the condition is true or false.

```
bc.condition(hasAntiLockBrakes, 0.95, 1.0)
```

This calculation would return 0.95 if the user has selected `Yes`

for the `hasAntiLockBrakes`

boolean Field. If they have not then it would return 1.0.

#### # `bc.if_item`

Returns different results based on whether the Risk has a specific Item checked.

```
bc.if_item('comprehensive', 0.95, 1.0)
```

This calculation would return 0.95 if the Comprehensive coverage is present on the Quote. If the coverage is not present then the calculation would return 1.0.

#### # `bc.round`

Rounds values based on a `round_to`

and `round_method`

.

```
bc.round(some_number, round_to=bc.NEAREST_HUNDRED, round_method=bc.ROUND_UP)
```

`bc.round`

also works with an alternative syntax:

```
bc.round(some_number, 2)
```

This is a simplified version that will round `some_number`

to the second decimal place.

##### # `round_to`

Options

`TWO_DECIMALS`

`ONE_DECIMAL`

`NEAREST_ONE`

`NEAREST_TEN`

`NEAREST_HUNDRED`

`NEAREST_THOUSAND`

Defaults to `TWO_DECIMALS`

(nearest penny)

##### # `round_method`

Options

`bc.ROUND_UP`

`bc.ROUND_DOWN`

`bc.ROUND_CEILING`

`bc.ROUND_FLOOR`

`bc.ROUND_HALF_UP`

Defaults to `bc.ROUND_HALF_UP`

(natural rounding)

#### # `bc.max`

Returns the maximum value from all values passed to it. If `primaryDriverRateTable`

resolves to 800.0
and `secondaryDriverRateTable`

resolves to 400.0 then the following function would return 800.0.

```
bc.max(primaryDriverRateTable, secondaryDriverRateTable)
```

#### # `bc.min`

Returns the minimum value from all values passed to it. If `primaryDriverRateTable`

resolves to 800.0
and `secondaryDriverRateTable`

resolves to 400.0 then the following function would return 400.0.

```
bc.min(primaryDriverRateTable, secondaryDriverRateTable)
```

### # Limits

Item's limits can be accessed in calculation by using `<itemName>.limits.<limitName>`

```
bodilyInjury.limits.bodilyInjuryLimit
```

## # Pro-Rata Premium Calculation

When a premium-bearing change is made to a policy mid-term, affected items must pro-rate the premium against the term. When a policy is canceled mid-term, items must be prorated based upon the cancellation effective date.

The Pro-Rata premium can be determined against different transaction types with different term lengths and granularity.

Pro-Rata premium is calculated and stored per Item. The total Policy Pro-Rata Premium and Policy Term Premium are also calculated and stored. The total Pro-Rata Premium and the Policy Term Premium, as well as each individual Item Pro-Rata premium and Policy Term Premium, are displayed in Rate Preview.

Pro-Rata premium calculation currently assumes a 1-year policy term with “day” granularity. Meaning that the premium is calculated to the day.

Total Pro-Rata Premium is calculated as the sum of all individual item pro-Rata premiums.

Pro-Rata Premium per Item is calculated as follows:

```
((units * (calculated rate - prior rate))/granularity) + prior pro-Rata premium
```

### # Example

- Term: 1 Year
- Effective Date: 1/1/2017
- Granularity: day (365 units for 1/1/2017 - 1/1/2018)

#### # Policy Inception - 1/1/2017

- Coverage A
- Full Term Amount: $365
- Variables:
- Units = days(1/1/2018 - 1/1/2017) = 365
- Calculated rate = 365
- Prior Rate = 0
- Prior Pro-Rata Premium = 0

- Pro-Rata Premium = ((365 * (365 - 0)) / 365) + 0 = $365

#### # Endorsement - 5/3/2017

- Coverage A
- Full Term Amount: $730
- Variables:
- Units = days(1/1/2018 - 5/3/2017) = 243
- Calculated rate = 730
- Prior Rate = 365
- Prior Pro-Rata Premium = 365

- Pro-Rata Premium = ((243 * (730 - 365)) / 365) + 365 = $608

#### # Endorsement - 9/2/2017

- Coverage A
- Full Term Amount: $1095
- Variables:
- Units = days(1/1/2018 - 9/2/2017) = 121
- Calculated rate = 1095
- Prior Rate = 730
- Prior Pro-Rata Premium = 608

- Pro-Rata Premium = ((243 * (730 - 365)) / 365) + 365 = $729