A canonical, well-specified, cross-language (Python + TypeScript) reference implementation of index initialization. An index starts with one decision: on this date, this basket is worth this many points. This module turns a basket, a base date and a base level into the market value, the divisor and the opening level — in exact decimal arithmetic, with every input factor checked on its own — and then shows what those three numbers leave out.
📖 Full article (canonical): Base-Date/Base-Value Initialization — The Fintech Builder
This repository is the runnable, production-oriented companion to that article. The article teaches the concept; this repo is the code you install and build on.
🧭 Browse all algorithms: Awesome FinTech Algorithms — the full index of the library.
🗂️ This algorithm's domain: Index and Benchmark Engineering › Index Initialization and Continuity
📥 Just want to call it? It also ships in the fintech-algorithms npm package — see Two ways to use this.
| Catalog topic | D03-F01-A01 |
| Domain | D03 — Index and Benchmark Engineering |
| Family | D03-F01 — Index Initialization and Continuity |
| Difficulty | 2 / 5 |
| Languages | Python, TypeScript |
| Opens | the D03 domain and the D03-F01 family |
- One decision, one relation
- Every factor is checked on its own
- Exact arithmetic
- Two ways to use this
- Install
- Quickstart
- Views: the analysis surface
- Input shape
- API reference
- Edge cases & limitations
- Testing
- Related algorithms
- License
Every level an index will ever publish is one relation:
level = market value / divisor
Initialization fixes it. On the base date, add up each member's float-adjusted market value in the index currency, choose a base level, and the divisor follows:
market value = sum(price x shares x floatFactor x fx)
divisor = market value / base level
On the base date the level is the base level. From then on, prices move the market value and the level moves with it; a corporate action or a membership change moves the market value too, and the divisor is adjusted so the level does not. That is the rest of this family.
Initialization on 2026-01-02
market value 119200
divisor 119.2
index level 1000
The reference engine checked only the total market value. Two consequences, both confirmed by running it:
- Sign errors cancel. A negative price times negative shares is a positive contribution, so two data errors produced a valid-looking index.
- Zero factors vanish. A zero fx rate or float factor silently removed a member's value from the base, while the member stayed in the basket.
Here price, shares and fx must each be positive, floatFactor must be in (0, 1], ids must
be unique non-blank strings, and baseDate — never read by the reference — must be a calendar-valid
YYYY-MM-DD.
One more refusal: a divisor that publishes as zero. A true divisor below 5e-7 rounds to 0 at six
decimals, which both reference twins returned. Nothing can be divided by it.
Every JSON number is read as the decimal its shortest round-trip spelling writes — 0.8 is exactly
4/5 — and all arithmetic runs in exact fractions (Fraction in Python, a bigint rational in
TypeScript). Rounding happens once, at publication: six decimals, half away from zero.
calculate({"constituents": [{"id": "X", "price": 1.0000005, "shares": 1, "floatFactor": 1, "fx": 1}],
"baseLevel": 1, "baseDate": "2026-01-02"})["divisor"]
# 1.000001 -- the written decimal is exactly on the half; its binary double is just below itThe published number is built from the rounded decimal string, so Python and TypeScript return the same double. Summing binary products instead, the reference's market values drifted by up to 1e-4 above ~1e11.
This repo is the production home: the full implementation, the analysis surface below, and 194 tests across two languages.
The fintech-algorithms npm package
ships the same topic as one import among several hundred.
fintech-algorithms/index-and-benchmark-engineering/index-initialization-and-continuity/base-date-base-value-initialization
Python
cd python
pip install -e ".[dev]"TypeScript
cd typescript
npm install
npm run buildfrom fintech_index_base import calculate, constituent_breakdown
request = {
"constituents": [
{"id": "ALFA", "price": 50, "shares": 1000, "floatFactor": 0.8, "fx": 1},
{"id": "BETA", "price": 80, "shares": 600, "floatFactor": 0.75, "fx": 1},
{"id": "GAMMA", "price": 40, "shares": 1200, "floatFactor": 0.9, "fx": 1},
],
"baseLevel": 1000,
"baseDate": "2026-01-02",
}
calculate(request)
# {'marketValue': 119200, 'divisor': 119.2, 'indexLevel': 1000}TypeScript is the same call:
import { calculate, constituentBreakdown } from 'fintech-index-base';
calculate(request); // { marketValue: 119200, divisor: 119.2, indexLevel: 1000 }Run the tour in either language:
cd python && python examples/quickstart.py
cd typescript && npm run exampleBoth print byte-identical output.
ALFA float value 40000 weight 0.335570 points 335.57047
BETA float value 36000 weight 0.302013 points 302.013423
GAMMA float value 43200 weight 0.362416 points 362.416107
weights sum to one: true points sum to the base level: true
levelPoints is each member's share of the base level. Both sums are checked exactly, not
within a tolerance.
The base level cannot move money between members, so the weights never change. What changes is how many decimals the divisor needs — and a divisor published to six decimals only reproduces the base level approximately when it does not terminate:
base 1 divisor 119200 exact in 0 dp level error from 6dp divisor 0
base 7 divisor 17028.571429 never terminates level error from 6dp divisor -0.000000000176174
base 1000 divisor 119.2 exact in 1 dp level error from 6dp divisor 0
base 10000 divisor 11.92 exact in 2 dp level error from 6dp divisor 0
Restates a level history on a new base date and level. Every level is multiplied by one exact
factor, so every period return is preserved, and returnsPreserved checks it exactly:
2026-01-02 1000 -> 98.765432
2026-01-05 1012.5 -> 100
2026-01-06 998.25 -> 98.592593
factor 0.098765432099 returns preserved: true
ok theMarketValueIsTheSumOfFloatValues
FAIL theDivisorIsMarketValueOverBaseLevel
ok theLevelOnTheBaseDateIsTheBaseLevel
FAIL thePublishedDivisorReproducesTheBaseLevel
That is a vendor file that published the divisor as 119. Pass a second argument to audit somebody
else's numbers; the last check divides the market value by the divisor as published and asks
whether the base level comes back.
Numbers must be JSON numbers: strings, booleans, NaN and infinities are refused.
Python — from fintech_index_base import ...
| function | returns |
|---|---|
calculate(data) / initialize_index(data) |
marketValue, divisor, indexLevel |
constituent_breakdown(data) |
per-member float value, weight and index points; exact sum checks |
base_level_sensitivity(data, base_levels=None) |
divisor, decimals needed and reproduction error per base level |
rebase_series(series, rebase_date, new_base_level) |
a restated level history and its exact factor |
verify_initialization(data, result=None) |
four checks; pass result to audit a supplied answer |
validate_request · validate_constituent · parse_date |
the validation steps, exposed |
to_fraction · render · number · trim · scaled |
the exact-arithmetic helpers |
TypeScript — import { ... } from 'fintech-index-base'
The same functions in camelCase (initializeIndex, constituentBreakdown, ...). Exact state is a
Rational with bigint numerator and denominator.
- Large published numbers are doubles. Above ~9e9 a six-decimal value is finer than a double can
hold, so the published number is the nearest double to the correctly rounded decimal. Weights and
reproduction errors are exact decimal strings for this reason. Python returns integral values as
int, which is exact beyond 2^53; JavaScript cannot. - The fx rate is yours to get right. It must convert the security's currency into the index currency at the base date; the module does not know currencies.
baseDateis validated, not used. No prices are fetched; the date labels the result.- A zero-weight member is refused, not ignored. Remove it from the basket instead.
rebase_seriesneeds the rebase date to be in the series — no interpolation between dates.- JSON integers beyond 2^53 reach TypeScript already rounded by
JSON.parse.
cd python && pytest -q # 97 tests
cd typescript && npm test # 97 testsBoth suites reproduce the canonical fixture byte for byte.
The two implementations were compared directly across 1,500 scenarios and 7,500 calls — the initialization and all four surfaces, valid and malformed — and their canonical JSON output is byte-identical. The exact-arithmetic modules were probed on 20,000 values, and the examples are byte-identical too.
The Python port was differentially tested against the reference engine on 12,000 generated
baskets with zero unexplained divergences. An independent Decimal oracle confirmed all 9,974
results the port returned. Every divergence is classified by name:
| divergence | cases | what happened |
|---|---|---|
| double resolution | 2,324 | both correct to the decimal; neighbouring doubles above ~9e9 |
| rounding rule | 1,246 | reference rounded a binary float; port rounds the exact decimal half away from zero |
| coercion | 449 | reference accepted strings and booleans |
| base date | 429 | reference never read baseDate |
| zero factor | 261 | reference let a zero fx or float factor erase a member |
| duplicate ids | 222 | reference did not check ids |
| sign cancellation | 206 | reference accepted negative price × negative shares |
| float bound | 156 | reference accepted a float factor above 1 |
| zero published divisor | 27 | reference returned a divisor of 0 |
| reference float accumulation | 12 | reference's binary sum drifted; port matches the oracle |
Same family — D03-F01 Index Initialization and Continuity
- Index Divisor Initialization — the divisor alone, how precisely to publish it, and how to recover it from published levels.
- Divisor Continuity Adjustment — keeping the level still when the market value changes for non-market reasons.
- Corporate-Action Divisor Bridge — the divisor across a special dividend, rights issue or spin-off.
- Intraday Index-Level Calculation — the level tick by tick, with a fixed divisor.
MIT — see LICENSE.
{ "constituents": [{ "id": "ALFA", // non-blank string, unique in the basket "price": 50, // > 0, in the security's currency "shares": 1000, // > 0, index shares "floatFactor": 0.8, // in (0, 1] "fx": 1 // > 0, security currency -> index currency, on the base date }], "baseLevel": 1000, // > 0 "baseDate": "2026-01-02" // calendar-valid YYYY-MM-DD }