Stock-Dividend Adjustment
Convert Price and Quantity Bases Without Inventing Value
Install and import#
npm install fintech-algorithmsimport { calculate } from "fintech-algorithms/corporate-actions-and-security-master-data/complex-distributions/stock-dividend-adjustment";Signature#
calculate(data)Applies a stock dividend, where shareholders receive additional shares instead of cash. Economically close to a split, but reported differently and often with a different volume convention — which is the part that gets missed.
Parameters#
| Name | Type | Notes |
|---|---|---|
data | { method: string; securityId: string; asOf: string; anchorAt: string; volumePolicy: string; events: Event[]; observations: Observation[] } | volumePolicy decides whether traded volume is restated alongside price; the two conventions are both in use and disagree. anchorAt fixes the basis date. Point-in-time by construction: asOf is the knowledge time, and only revisions available at or before it are eligible. Passing the event date instead of the knowledge date is what lets a backtest use information it could not have had. |
Returns#
{ method, appliedEvents, unavailableEventIds, cancelledEventIds, observations, … }
Adjusted observations plus which events were applied, which were not yet knowable, and which were cancelled — a cancelled event that silently still applies is a class of bug this makes visible.
Errors#
- When the volume policy or method is unrecognised — throws
Complexity: time O(n + e),
space O(n).
Worked example#
verified This is the worked example published in the article, replayed by the test suite on every run. The output cannot drift.
Input#
{
"method": "backward_post_event_same_class",
"securityId": "SYNTH-CLASS-A",
"asOf": "2026-02-04T12:00:00Z",
"anchorAt": "2026-02-03T21:00:00Z",
"volumePolicy": "adjust_to_anchor_basis",
"events": [
{
"eventId": "SD-001",
"subjectSecurityId": "SYNTH-CLASS-A",
"distributedSecurityId": "SYNTH-CLASS-A",
"exAt": "2026-01-15T14:30:00Z",
"recordDate": "2026-01-15",
"payableDate": "2026-01-20",
"revisions": [
{
"publishedAt": "2026-01-05T18:00:00Z",
"status": "confirmed",
"rateNewSharesPerOld": 0.1,
"sourceId": "SYNTH-NOTICE-1"
}
]
},
{
"eventId": "SD-002",
"subjectSecurityId": "SYNTH-CLASS-A",
"distributedSecurityId": "SYNTH-CLASS-A",
"exAt": "2026-02-03T14:30:00Z",
"recordDate": "2026-01-30",
"payableDate": "2026-02-02",
"revisions": [
{
"publishedAt": "2026-01-20T18:00:00Z",
"status": "confirmed",
"rateNewSharesPerOld": 0.15,
"sourceId": "SYNTH-NOTICE-2-R1"
},
{
"publishedAt": "2026-01-25T18:00:00Z",
"status": "confirmed",
"rateNewSharesPerOld": 0.2,
"sourceId": "SYNTH-NOTICE-2-R2"
}
]
}
],
"observations": [
{
"at": "2026-01-02T21:00:00Z",
"availableAt": "2026-01-02T21:00:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"price": 50,
"shares": 200,
"volume": 80
},
{
"at": "2026-02-02T21:00:00Z",
"availableAt": "2026-02-02T21:00:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"price": 55,
"shares": 220,
"volume": 90
},
{
"at": "2026-02-03T14:30:00Z",
"availableAt": "2026-02-03T14:30:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"price": 46,
"shares": 264,
"volume": 100
}
]
}Call#
calculate(data)Returns#
object with 9 fields: method, securityId, asOf, anchorAt, volumePolicy, appliedEvents, unavailableEventIds, cancelledEventIds, …
{
"method": "backward_post_event_same_class",
"securityId": "SYNTH-CLASS-A",
"asOf": "2026-02-04T12:00:00Z",
"anchorAt": "2026-02-03T21:00:00Z",
"volumePolicy": "adjust_to_anchor_basis",
"appliedEvents": [
{
"eventId": "SD-001",
"exAt": "2026-01-15T14:30:00Z",
"revisionPublishedAt": "2026-01-05T18:00:00Z",
"knownByExDate": true,
"rateNewSharesPerOld": 0.1,
"shareFactor": 1.1,
"priceFactor": 0.909090909091,
"sourceId": "SYNTH-NOTICE-1"
},
{
"eventId": "SD-002",
"exAt": "2026-02-03T14:30:00Z",
"revisionPublishedAt": "2026-01-25T18:00:00Z",
"knownByExDate": true,
"rateNewSharesPerOld": 0.2,
"shareFactor": 1.2,
"priceFactor": 0.833333333333,
"sourceId": "SYNTH-NOTICE-2-R2"
}
],
"unavailableEventIds": [],
"cancelledEventIds": [],
"rows": [
{
"at": "2026-01-02T21:00:00Z",
"availableAt": "2026-01-02T21:00:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"rawPrice": 50,
"adjustedPrice": 37.878787878788,
"rawShares": 200,
"adjustedShares": 264,
"rawVolume": 80,
"adjustedVolume": 105.6,
"cumulativeShareFactor": 1.32,
"appliedEventIds": ["SD-001", "SD-002"]
},
{
"at": "2026-02-02T21:00:00Z",
"availableAt": "2026-02-02T21:00:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"rawPrice": 55,
"adjustedPrice": 45.833333333333,
"rawShares": 220,
"adjustedShares": 264,
"rawVolume": 90,
"adjustedVolume": 108,
"cumulativeShareFactor": 1.2,
"appliedEventIds": ["SD-002"]
},
{
"at": "2026-02-03T14:30:00Z",
"availableAt": "2026-02-03T14:30:05Z",
"sourceId": "SYNTH-CLOSES-V1",
"rawPrice": 46,
"adjustedPrice": 46,
"rawShares": 264,
"adjustedShares": 264,
"rawVolume": 100,
"adjustedVolume": 100,
"cumulativeShareFactor": 1,
"appliedEventIds": []
}
]
}Other exports#
This module also exports
settleEntitlement, roundOutput. Every module additionally exports run as an alias of its
primary function, and a meta object carrying its catalog id, domain, family,
shape and article URL.
Diagrams#
Calculation flow#
Revision selection and adjustment flow
flowchart LR
A["Raw event revisions"] --> B["Keep publishedAt not later than asOf"]
B --> C["Choose latest unique revision"]
C --> D{"Status and class valid?"}
D -->|Cancelled| E["Report cancellation"]
D -->|Wrong class| F["Reject method"]
D -->|Confirmed same class| G{"Observation before exAt?"}
G -->|No| H["Keep new-basis row"]
G -->|Yes| I["Compound factor"]
I --> J["Divide price"]
I --> K["Multiply shares"]
I --> L["Adjust or preserve volume"]
J --> M["Audited output"]
K --> M
L --> M
Event evidence lifecycle
stateDiagram-v2
[*] --> Unavailable
Unavailable --> Announced: first publication
Announced --> Confirmed: authoritative terms
Announced --> Cancelled: source cancellation
Confirmed --> Effective: exAt reached
Confirmed --> Revised: later publication
Revised --> Confirmed: terms replace prior revision
Revised --> Cancelled: later cancellation
Effective --> Restated: later correction selected by current asOf
Effective --> Historical: earlier asOf retains earlier evidence
Cancelled --> [*]
Restated --> [*]
Historical --> [*]
How it works#
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References#
- R1 - NVIDIA 2021 stock-split announcement filed with the SEC — NVIDIA Corporation
- R2 - NVIDIA 2021 Stock Split FAQ — NVIDIA Corporation
- R3 - FINRA Rule 11140 — Financial Industry Regulatory Authority
- R4 - Nasdaq Daily List File Format and Specifications — Nasdaq
- R5 - FTSE Russell Corporate Actions and Events Guide for Market Capitalisation Weighted Indices — FTSE Russell, LSEG
- R6 - S&P DJI Index Mathematics Methodology — S&P Dow Jones Indices
- Evidence classification