Skip to content
All posts
ConfigurationInsurers

How a premium is calculated

Rate strategies, what each row works on, the carry-forward rule, gated extensions, proration, currency, tax, commission and rounding, with numbers.

The BimaStack team · · 7 min read

Behind every rate card is the same small set of rules: how a rate turns an amount into a premium, which amount each line works on, the order lines are applied in, and how the result is prorated, converted, taxed and rounded. BimaStack carries these rules forward from the systems insurers already trust, and runs them as ordinary workflows and blocks. This post explains each one, with numbers.

A premium is many small rows

A premium isn’t one big formula. It is a list of rate rows, each worked out by the strategy that row declares and folded into a running total, in a strict order:

The shape of every premium
for each group of rows (a section, a cover type or a binder), in strict order:
    for each row:
        choose the amount it works on (the sum insured, or the total so far)
        work out its contribution with the row's strategy
        add it to, or take it from, the running total
    emit the group's total, rounded

Tax and commission are two more passes of the same shape, run on the premium once it is known.

Rate strategies

Strategy Rule Example
FixedA flat amount, or a flat percentage of the amountA policy fee of KES 500, whatever the sum insured
Absolute rangeOnce the amount falls in a band, the band’s rate applies to all of it0–1,000,000 at 2%: 800,000 gives 16,000
Absolute range, age-bandedThe same, with an age bandPersonal accident by age of the insured
Absolute range, special bandedThe same, on another count (members, headcount)A scheme rated by number of lives
Recurring (tiered) rangeEach band’s rate applies only to the part of the amount inside it, like income-tax brackets0–100,000 at 1% and 100,000–500,000 at 0.5%: 300,000 gives 1,000 + 1,000 = 2,000
Step rangeThe band’s width is what is charged, once the amount reaches itA band of 50 seats at a per-seat rate: 50 × rate

A tiered range is configured as one rate row per band, each using the same step formula, max(min(amount, bandTo) − bandFrom, 0) × rate, and summed. One row, one band, one mental model, for every strategy.

One row, in order

Besides its rate, every row may carry a multiplier and divisor, a free limit, a minimum and a proration type. They are applied in a fixed order:

  1. 1

    Convert the currency

    If the row’s rate is in another currency, at the published rate for the pair, the same rate for the whole calculation.

  2. 2

    Take off the free limit

    The strategy never sees the excluded part. A benefit rated at 10% with an 80,000 free limit, on a value of 90,000: 10% of 10,000 is 1,000.

  3. 3

    Apply the strategy

    With the multiplier and divisor.

  4. 4

    Apply the minimum

    The row’s contribution is at least its minimum: max(result, minimum).

  5. 5

    Prorate

    Full term, prorated by days, or by a short-period scale.

What each row works on: its role

Roles Work on Effect
Sum insured, section limit, extension limit, extension sum insured, medical limit, occupation limitThe amount givenEstablish the premium
Loading, escalation, risk loadings (vehicle age, cubic capacity, seat capacity, earthquake)The total so farAdd
Discount, no-claim discountThe total so farTake off
Excess protectorThe total so far, by defaultAdd

Each role has a default amount to work on, and any row may override it. Excess protector shows why: the general rule says the running total, but real schemes charge it on the vehicle’s value (0.25% of the value). Both are the same setting on the row.

The carry-forward rule

The single most important rule, and the easiest to get wrong: loadings and discounts work on the total built by every earlier row in the group, not on the sum insured.

Row Works on Contribution Total
Base premiumSum insured10,00010,000
Loading +10%10,000+1,00011,000
Discount −5%11,000−55010,450

Because order changes the answer, rows within a group must have one unambiguous order. A group whose order can’t be decided is refused, never computed in whatever order the data arrived. In a workflow this is the aggregate chain: each step names the total it builds on.

Optional rows are gated

A no-claim discount applies only when the quote says the policy is eligible, at a level that matches the row. An excess protector applies only when the client opted in. The same goes for any optional extension (terrorism, road rescue, loss of use): the row is in the table, but contributes only when its eligibility flag is set, and shows as zero otherwise.

A gated NCD row
if(ncd.eligible and ncd.level == rate.ncdLevel, -1 * runningTotal * rate.value, 0)

Proration

Type Contribution for a shorter cover
Full termUnchanged
ProratedScaled by days ÷ 365
Short periodA percentage from a day-band scale: short covers aren’t charged proportionally less, because the risk doesn’t fall in proportion

Proration is applied per row, before the row joins the running total, so later loadings work on prorated amounts.

Tax and commission

  • Tax is a second pass over the finished premium: each tax row (a training levy, a policyholders’ compensation fund levy, stamp duty) is rated with the same strategies, without roles.
  • Commission is a third pass, worked out on premium and tax, owed to whoever placed the business. It can be worked out with the quote or later, per distributor type.
  • The client pays premium plus tax. Commission is never part of the client’s total.

Rounding

  • No floating point, anywhere money or rates are handled.
  • Ten decimal places carried through every intermediate step.
  • Half to even for division and final rounding: it avoids the upward drift that rounding half up adds over many quotes.
  • Round only at the edges: a group’s total, the tax total, the commission total, an amount shown or stored. A running total is never rounded part way.

Fail closed

A calculation stops with a clear error, never a best guess, when rows can’t be put in order, a rate or formula has no version in effect on the date, a formula fails as it runs, or an outside call fails.

How BimaStack runs these rules

None of this is fixed code. Each rule above is configured in a product’s pricing workflow, from pieces you author:

Rule Configured as
Rates, bands, minimumsRate tables, read with a table-rate block
A strategyA formula: value * rate / 100 for a percentage, max(min(value, bandTo) - bandFrom, 0) * rate for a tier
Free limit, minimummax(value - freeLimit, 0) before the strategy, max(result, minimum) after
Carry-forwardAn aggregate chain: each loading or discount works on the previous total
Gated extensionsif(chosen, amount, 0) in a formula, or a decision that skips a whole section
Prorationprorate() for full term and pro rata; a rate table banded by days for a short-period scale
Currencyconvert(), at the published rate for the whole calculation
Tax and leviesA rate table of levy rates on the net premium, rounded before adding

Each rate, each formula and each running total appears in the trace, so the breakdown of any quote answers “why is this number what it is”.

Check us against your own numbers

Send a rate card and a worked quote; we’ll reproduce it.

Book a demo