One sum, five engines, one answer
Five JavaScript engines disagree about the last bit of exp, log, sin and tan. We built the kernel from operations they cannot disagree about, and run all five.
Tomasz Wierzbicki6 min read
Calculation engines for FRTB, SIMM, Solvency II and eight more regimes. Every result carries its derivation, the clause it implements and a receipt that reproduces on any machine.
The receipt
Every figure comes with the working that produced it, line by line.
The clause that it implements sits beside the number it gives.
Statements are proved and tested, and the ledger says which.
A receipt that any machine can check, with no client data.
In production
From global banks and reinsurers to vehicle makers and validation laboratories.
Why GraphAtlas
Regulation is written in prose and enforced in arithmetic.
Between the two sits a spreadsheet that nobody can fully explain, and a number that is only as good as the person who last opened it.
GraphAtlas replaces the spreadsheet with engines that carry their own derivation.
Each figure comes with the clause it implements, the working that produced it and a receipt that any machine can check.
5.8 h, down from 4.2 days h
Median time to settle a margin dispute at a major UK bank, down from 4.2 days.
When a counterparty’s number differs from ours, we no longer argue about whose model is right. We open the same file and the difference is already ranked by line.
How a number is made
A figure is only worth something if someone else can check it. We build every engine so that they can.
The rule
A regulation is a set of paragraphs. We turn each one into a small typed function, with its parameters in the open and the clause beside it. Nothing hidden sits between the text and the number.
export function scenarioCorrelation(rho: number, scenario: Scenario): number {
switch (scenario) {
case 'medium':
return rho;
case 'high':
return Math.min(1.25 * rho, 1);
case 'low':
return Math.max(2 * rho - 1, 0.75 * rho);
}
} The receipt
Engines disagree about the last digits of exp and log. Our kernel never calls them. Every result is hashed from the bit patterns of its numbers, so a run in a browser, at the edge or on a server gives one receipt.
Receipt of the sample book, by engine
| Engine | Version | Receipt, first 16 digits | Same as the first |
|---|---|---|---|
| Node.js | 25.2.1 | deab796a 4e2b81f9 | |
| workerd (Cloudflare Workers) | 1.20261023.1 | deab796a 4e2b81f9 | |
| Chromium | 156.0.8078.4 | deab796a 4e2b81f9 | |
| Firefox | 157.0 | deab796a 4e2b81f9 | |
| WebKit | 27.2 | deab796a 4e2b81f9 |
5 of 5 engines agree, on this build.
The split
A capital charge is a square root, so it does not add up by position. The engine splits it so that each currency, tenor and trade receives the part that rests on it, and the parts sum to the total with nothing left over.
Share of the 36,584,378 dollar charge, largest seven of twenty factors
Shares sum exactly to the charge.
The evidence
Each statement about an engine is proved, certified or tested, and says which. The proofs are files that you can rerun with another solver, and the receipts are hashes that you can recompute on a machine of your own.
The catalogue
Each product encodes a regulation as typed rules with the clause attached. They share one numerical core, so a number in the margin product can be compared with the same number in the capital product, bit for bit.
Try it
This is the engine that produced the receipt at the top of the page, running in your browser. Edit any PV01 and the charge, the split and the receipt are worked again. Nothing leaves the page.
Fig. 1 GIRR delta capital for an illustrative two-currency book
Verifying receipt
Capital charge, USD
36,584,378 US dollars
The charge is the highest of three correlation scenarios. Low correlation binds.
Correlations cut to 2ρ − 1 or 75% of ρ, whichever is larger.
| Bucket and tenor | PV01 | Weighted | Share | Share, drawn to scale |
|---|---|---|---|---|
| K 34.32m | 33,903,114 | |||
| 918,000 | 637,702 | |||
| 2,142,000 | 1,867,707 | |||
| 5,952,000 | 5,776,397 | |||
| 12,402,000 | 11,610,487 | |||
| 8,136,000 | 6,981,665 | |||
| 31,845,000 | 23,907,478 | |||
| −23,496,000 | −12,325,828 | |||
| −8,019,000 | −3,227,700 | |||
| −6,237,000 | −1,998,301 | |||
| 3,201,000 | 673,507 | |||
| K 5.98m | 2,681,264 | |||
| Charge, low scenario | 36,584,378 | Shares sum exactly | ||
| Shares sum exactly | ||||
Customers
Banks, insurers, vehicle makers and laboratories, in their own words and with their own figures.
In their words
Rerunning last quarter bit for bit used to take a week and three people. Now it is one command and a hash that matches.
Every option combination gets its own CO₂ figure, and the technical service can trace each one to the test it came from.
Desk heads used to ask what the model was doing to them. Now they ask what their positions are doing to the model, which is the right question.
The estimator output matched the validation lab to the last digit. We stopped arguing about whose tool was right.
Distributors used to query our risk indicators every quarter. Now we send them the receipt, and the query is closed before it is opened.
Platform
One kernel, three places to run it. The choice is about where the data can go, and it never changes the answer.
The kernel is plain TypeScript with no dependencies. It runs in the page, so a trader can change a position and watch the charge move without a network call, and the figures never leave the machine.
The same code runs on Cloudflare Workers, near the user. What you send goes over TLS, is worked on in memory and is not stored, and a public endpoint recomputes any receipt you give it.
A signed container image and language packages run inside your own network, including air-gapped sites, and return the same receipts as the hosted service.
Send the inputs of a calculation and receive the answer with its receipt. Send a receipt that you were given and the answer says whether the two match, and by how many bits they differ if they do not.
curl https://graphatlas.com/api/verify \
--header 'content-type: application/json' \
--data '{"kind":"present-value","input":{"cashflows":[100,100,1100],"ratePercent":4.5}}' {
"kind": "present-value",
"receipt": "01cb05ef1a8b46f414173d0a332e117258339dfa6b1b2c48ec9e97bc3c95c5a5",
"result": {
"presentValue": 1148.0803695672707
}
} Research
Essays by the people who build and check the engines, on numerics, verification, regulation and security.
Five JavaScript engines disagree about the last bit of exp, log, sin and tan. We built the kernel from operations they cannot disagree about, and run all five.
Tomasz Wierzbicki6 min read
A receipt shows that a calculation can be redone, not who did it. Why a hash and not a signature, why numbers are hashed as bits, and what a match tells you.
Dr Anneliese Okafor and Jonas Falk4 min read
A capital charge is a square root, so it does not add up by position. How the engine splits it exactly, and what the page does when it rounds the pieces.
Marcus Teller and Tomasz Wierzbicki6 min read
The next step
A scoping call, a sample book and a parallel run on your data. Most teams have the first reconciled number inside two weeks, and a receipt for it on the day.