Pricing — the formulas

Two worked examples carry this page:

Every formula is quoted from source. Every number is recomputed from the operands shown. Where a test pins the number, the test is named.

Part 1 — the statistics of a simulated distribution

Source: Pricing/SimulationResult/Source/SimulationResult.cs. Take the C# fixture's gross loss S1-GrossLoss from Pricing/SampleData/Source/SamplePricings.cs: the distribution is {10, 20, 30, 40, 50}.

Mean

Mean = Distribution.Length == 0 ? 0 : Distribution.Sum() / Distribution.Length

(10 + 20 + 30 + 40 + 50) / 5 = 150 / 5 = 30. The test EmbeddedResults_ExposeStatistics pins "gross mean = 30".

Standard deviation (population, divide by n)

variance          = Distribution.Sum(x => (x - mean) * (x - mean)) / Distribution.Length
StandardDeviation = Math.Sqrt(variance)          // 0 for an empty distribution

The deviations are −20, −10, 0, 10, 20. Their squares are 400, 100, 0, 100, 400, which sum to 1,000.

This is the population form, dividing by n and not by n − 1. The sample form would give √250 = 15.81. The test MeanAndStdDev_AreCorrect pins {1, 2, 3, 4, 5} → standard deviation √2.

Quantile (empirical VaR, linear interpolation between order statistics)

if (p <= 0) return sorted[0];   if (p >= 1) return sorted[^1];
h  = (n - 1) * p;   lo = floor(h);   hi = ceil(h)
Quantile(p) = sorted[lo] + (h - lo) * (sorted[hi] - sorted[lo])

For p = 0.9 on {10, 20, 30, 40, 50}:

p h Quantile
0.5 2.0 30 (the test pins "gross median = 30")
0.9 3.6 46
0.99 3.96 40 + 0.96 × 10 = 49.6
≤ 0 or ≥ 1 — clamps to 10 / 50 (test Quantile_IsEmpiricalVaR)

This interpolation differs from the stop-loss engine's nearest-rank Percentile (Loss Modelling formulas). On the same five draws, nearest rank gives sorted[ceil(0.9 × 5) − 1] = sorted[4] = 50.

The same statistics on the shipped node

The SamplePriceProgram node's results (the node carries different draws from the C# fixture):

Result Draws Mean Std dev Q(0.5) Q(0.9)
S1-GrossLoss 20, 45, 70, 95, 140 74 √1,714 = 41.40 70 95 + 0.6 × 45 = 122
S1-CededLoss (40 xs 60) 0, 0, 10, 35, 40 17 √296 = 17.20 10 35 + 0.6 × 5 = 38
fixture S1-CededLoss 0, 0, 5, 15, 25 9 (test pins "ceded mean = 9") √94 = 9.70 5 21

The node's ceded mean is 17, which is 23 % of the gross mean of 74. These are illustrative draws. They apply only the 40 xs 60 layer. The linked section also carries an annual aggregate deductible of 5 and an annual aggregate limit of 120, which they do not apply. So 17 is not the expected loss under the section's full terms.

Part 2 — the program's total reinsurance premium

Source: Pricing/Program/Source/Program.cs.

TotalReinsurancePremium(premiumByAcceptanceId) =
    AcceptancesById.Keys.Sum(id => premiumByAcceptanceId.TryGetValue(id, out var premium) ? premium : 0d)

The premiums live on the acceptance nodes, so the caller resolves them and passes the map in. An acceptance missing from the map contributes 0.

Worked: the fixture SamplePricings.AcceptancePremiums() gives PropertyCat2023 1,200,000 and PropertyRisk2023 450,000. The total is 1,200,000 + 450,000 = 1,650,000; the test TotalReinsurancePremium_SumsAcceptances pins it. With only PropertyCat2023 in the map the total is 1,200,000. An empty Program gives 0.

Those two premiums are fixture values: in source they are described as "as they would be read off the acceptance nodes". The shipped acceptance nodes carry cover × premiumRate instead: PropertyCat2023 is 40 × 0.25 = 10, and PropertyRisk2023 is 20 × 0.15 = 3. No code in Pricing derives the map from the nodes.

Part 3 — the underwriting guideline

Sources: Pricing/Guideline/Source/Guideline.cs (the scope), PricingChecks.cs (the rules as RuleResults), GuidelineTables.cs (the caps and the rating ladder) and RuleResult.cs. The proxy memoises every member, so a member that others read (Escalations) is evaluated once.

The placement is the sample compliance check: Property Cat, gross line €62,000,000, combined ratio 1.08, 24 months, cedent A-, standard wording. Its live Compliance area renders the table below.

Note: the Compliance area always evaluates the built-in sample, GuidelineSampleData.Sample() (Pricing/Guideline/Source/ComplianceArea.cs), not the content of the node it is opened on. The sample node holds the same values, so the table matches it here. On any other Guideline node it still shows this sample.

Subscribers see this result live; below is the same worked example as a static table.

Property Cat · gross line €62,000,000 · combined ratio 108.0 % · term 24 months · cedent A-

Guideline check Result
Four eyes (§4.2): gross line ≥ 4m ❌ second underwriter
Capacity (§4.2): gross line > 50m ❌ CUO
Line-of-business cap (§6): Property Cat 50m ❌ CUO
Loss making (§8): combined ratio > 105 % ❌ CUO
Below profitability (§6.1): 100 % < combined ratio ≤ 105 % ✅
Multi-year (§10): term > 36 months ✅
Weak cedent (§7): below BBB- ✅
Wording deviation (§10.1) ✅
Verdict ⚠️ Refer to CUO
Share action ⬇️ Decrease

This summarises the outcome of each rule. The live area prints each rule's own sentence instead. The outcomes are the ones the test ReferToCuo_TheSample pins.

The checks, one by one

Member Formula as in source Sample Trips?
FourEyes (§4.2) GrossLine >= 4_000_000 62m ≥ 4m yes, so SecondUnderwriter
Capacity (§4.2) > 100_000_000 → UnderwritingCommittee; > 50_000_000 → Cuo; else None 62m > 50m, ≤ 100m Cuo
LoBCapBreached (§6) LobCap(state) is double cap && GrossLine > cap "Property Cat" → key propertycat → 50,000,000; 62m > 50m yes, so Cuo
LossMaking (§8) CombinedRatio > 1.05 1.08 > 1.05 yes, so Cuo
BelowProfitability (§6.1) CombinedRatio > 1.00 && CombinedRatio <= 1.05 1.08 > 1.05 no
MultiYear (§10) TermMonths > 36 24 no
WeakCedent (§7) RatingNotch(rating) > 9 (BBB- / Baa3 is notch 9) A- is notch 6 no
WordingDeviation (§10.1) MandatoryExclusionRemoved \|\| NonStandardClause false, false no

LobCap(state) reads state.Caps when it is non-empty: the row whose Label or an Alias normalises to the same key, giving its MaxGrossLine. Otherwise it reads the built-in §6 table. The key is lower-case and alphanumerics only. A line of business in neither has no cap: the §6 rule then reports NoData, and LoBCapBreached stays false.

The rating ladder is index-aligned:

An unknown rating has no notch, so it is not "weak". An empty rating reports NoData on §7.

Escalations, verdict, share action

Escalations = (FourEyes ? SecondUnderwriter : None) | Capacity | (LossMaking ? Cuo : None)
            | (BelowProfitability ? HeadOfLoB : None) | (MultiYear ? Cuo | UnderwritingCommittee : None)
            | (WeakCedent ? Cuo : None) | (WordingDeviation ? Cuo | Legal : None) | (LoBCapBreached ? Cuo : None)
EscalatesToCuoOrCommittee = (Escalations & (Cuo | UnderwritingCommittee)) != None
Verdict     = CombinedRatio > 1.20 ? Decline
            : (CombinedRatio > 1.05 || EscalatesToCuoOrCommittee) ? ReferToCuo : Write
ShareAction = Verdict == Decline ? Decline : Verdict == ReferToCuo ? Decrease
            : CombinedRatio < 0.85 ? Increase : Maintain

Worked:

  1. Escalations = SecondUnderwriter | Cuo = flags 1 + 4 = 5.
  2. Verdict: is 1.08 > 1.20? No. Is 1.08 > 1.05? Yes. So ReferToCuo.
  3. Share action: Decrease.

The test ReferToCuo_TheSample pins exactly this: trips {FourEyes, Capacity, LossMaking, LoBCapBreached}, capacity Cuo, verdict ReferToCuo, share Decrease.

The rule result (RuleResult)

Each clause is one value. It is built fluently: RuleResult.For(clause, title), then .Escalating(e), .NoDataWhen(...), .BreachedWhen(cond, because) and .Noting(...).

On the sample, four rows are ✗: §4.2 ×2, §6 and §8. Four are ✓: §6.1, §10, §7 and §10.1.

Check yourself

Q1. Recompute the sample placement with a combined ratio of 1.03 and a gross line of €45,000,000. Everything else stays the same. What are the trips, the verdict and the share action?

A1.

Escalations = SecondUnderwriter | HeadOfLoB, which reaches neither Cuo nor the Committee. The verdict is Write. The share action is Maintain, because 1.03 is not < 0.85. The test BelowProfitability_StaysWrite pins that a Head-of-LoB escalation alone keeps the verdict at Write.

Q2. What is Quantile(0.25) of the node's gross draws {20, 45, 70, 95, 140}?

A2. h = 4 × 0.25 = 1.0, so lo = hi = 1, and the quantile is sorted[1] = 45.

Reference

Member Formula File Pinned by
SimulationResult.Mean Σx / n, 0 if empty SimulationResult/Source/SimulationResult.cs MeanAndStdDev_AreCorrect, EmbeddedResults_ExposeStatistics
SimulationResult.StandardDeviation √(Σ(x − mean)² / n) same MeanAndStdDev_AreCorrect
SimulationResult.Quantile(p) s[lo] + (h − lo)(s[hi] − s[lo]), h = (n−1)p, clamped same Quantile_IsEmpiricalVaR
Program.TotalReinsurancePremium Σ premium[id] over AcceptancesById, missing = 0 Program/Source/Program.cs TotalReinsurancePremium_SumsAcceptances
Program.Address pricing/{Id} Program/Source/Program.cs, Source/PricingAddress.cs Address_AndPricingAddress
Guideline.FourEyes … LoBCapBreached see the table above Guideline/Source/Guideline.cs GuidelineTests (Boundaries_AreExact pins every threshold)
Guideline.Escalations / Verdict / ShareAction see above Guideline/Source/Guideline.cs GuidelineTests
PricingChecks.Evaluate one RuleResult per clause Guideline/Source/PricingChecks.cs GuidelineTests
GuidelineTables.LobCap / IsBelowInvestmentGrade state caps ▸ §6 table; notch > 9 Guideline/Source/GuidelineTables.cs GuidelineTests

Related:

Reconnecting…
The connection to the server was interrupted. Trying to restore it…
Trying again…
The connection could not be restored. Reloading the page…
The server was updated. Reloading the page to pick up the latest version.