Special-Dividend Adjustment
Preserve Return Meaning Across the Ex-Date
Install and import#
npm install fintech-algorithmsimport { calculate } from "fintech-algorithms/corporate-actions-and-security-master-data/complex-distributions/special-dividend-adjustment";Signature#
calculate(rawData)Handles a distribution large or irregular enough that treating it as an ordinary dividend misstates the series. The hard part is not the arithmetic but the classification, and this makes that decision explicit and auditable.
Parameters#
| Name | Type | Notes |
|---|---|---|
rawData | { securityId: string; eventId: string; asOf: string; methodology: string; eventRevisions: EventRevision[]; referencePrice: object; precedingActions: object[]; fxRate?: object; taxProfile?: object; exPriceObservation?: object } | precedingActions matters because adjustments compose in order — a split applied before or after this distribution gives different answers. fxRate and taxProfile cover cross-currency distributions and withholding. 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#
{ eventState, classificationDecision, classificationReason, adjustmentApplied, grossDividendOnEventBasis, netDividendOnEventBasis, … }
The classification *and the reason for it*, alongside gross and net amounts on the event's own basis. The reason is the point: this is a judgement, and a judgement without its rationale cannot be reviewed.
Errors#
- When the methodology is unrecognised — throws
Complexity: time O(revisions + actions),
space O(1).
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#
{
"securityId": "SYNTHETIC-SECURITY-004",
"eventId": "SYNTHETIC-SPECIAL-DIVIDEND-2026-01",
"asOf": "2026-03-16T20:10:00Z",
"methodology": {
"id": "SYNTHETIC-NET-RETURN-POLICY",
"version": "1.0",
"sourceId": "SYNTHETIC-METHODOLOGY-NOTE",
"classificationMode": "source-designated",
"priceAdjustmentCashBasis": "net",
"referenceAnchor": "previous-session-official-close",
"outputDecimals": 8
},
"eventRevisions": [
{
"revisionId": "R1",
"securityId": "SYNTHETIC-SECURITY-004",
"eventId": "SYNTHETIC-SPECIAL-DIVIDEND-2026-01",
"status": "announced",
"issuerClassification": "special",
"grossAmount": 15,
"currency": "EUR",
"announcedAt": "2026-02-02T12:00:00Z",
"availableAt": "2026-02-02T12:05:00Z",
"exAt": "2026-03-16T13:30:00Z",
"paymentAt": "2026-03-20T12:00:00Z",
"actionOrder": 20,
"amountBasisOrder": 0,
"sourceId": "SYNTHETIC-ISSUER-NOTICE-R1"
},
{
"revisionId": "R2",
"securityId": "SYNTHETIC-SECURITY-004",
"eventId": "SYNTHETIC-SPECIAL-DIVIDEND-2026-01",
"status": "announced",
"issuerClassification": "special",
"grossAmount": 16,
"currency": "EUR",
"announcedAt": "2026-02-05T14:00:00Z",
"availableAt": "2026-02-05T14:10:00Z",
"exAt": "2026-03-16T13:30:00Z",
"paymentAt": "2026-03-20T12:00:00Z",
"actionOrder": 20,
"amountBasisOrder": 0,
"sourceId": "SYNTHETIC-ISSUER-NOTICE-R2"
}
],
"referencePrice": {
"value": 100,
"currency": "USD",
"anchorType": "previous-session-official-close",
"anchorAt": "2026-03-13T20:00:00Z",
"observedAt": "2026-03-13T20:00:00Z",
"availableAt": "2026-03-13T20:00:05Z",
"sourceId": "SYNTHETIC-OFFICIAL-CLOSE"
},
"precedingActions": [
{
"actionId": "SYNTHETIC-2-FOR-1-SPLIT",
"actionOrder": 10,
"priceFactor": 0.5,
"perShareAmountFactor": 0.5,
"effectiveAt": "2026-03-16T13:30:00Z",
"observedAt": "2026-02-01T10:00:00Z",
"availableAt": "2026-02-01T10:05:00Z",
"sourceId": "SYNTHETIC-ACTION-SOURCE"
}
],
"fxRate": {
"baseCurrency": "EUR",
"quoteCurrency": "USD",
"rate": 1.1,
"observedAt": "2026-03-13T20:00:00Z",
"availableAt": "2026-03-13T20:00:05Z",
"sourceId": "SYNTHETIC-FX-CLOSE"
},
"taxProfile": {
"withholdingRate": 0.25,
"jurisdiction": "SYNTHETIC-JURISDICTION",
"investorCategory": "SYNTHETIC-NONRESIDENT",
"observedAt": "2026-01-05T09:00:00Z",
"availableAt": "2026-01-05T09:05:00Z",
"sourceId": "SYNTHETIC-TAX-RULE"
},
"exPriceObservation": {
"value": 43.75,
"currency": "USD",
"observedAt": "2026-03-16T20:00:00Z",
"availableAt": "2026-03-16T20:00:05Z",
"sourceId": "SYNTHETIC-EX-CLOSE"
}
}Call#
calculate(rawData)Returns#
object with 16 fields: eventState, selectedRevisionId, classificationDecision, classificationReason, adjustmentApplied, referencePriceOnEventBasis, grossDividendOnEventBasis, netDividendOnEventBasis, …
{
"eventState": "effective",
"selectedRevisionId": "R2",
"classificationDecision": "special",
"classificationReason": "source designation: special",
"adjustmentApplied": true,
"referencePriceOnEventBasis": 50,
"grossDividendOnEventBasis": 8.8,
"netDividendOnEventBasis": 6.6,
"adjustmentCashAmount": 6.6,
"theoreticalExPrice": 43.4,
"adjustmentFactor": 0.868,
"grossDistributionYield": 0.176,
"methodologyId": "SYNTHETIC-NET-RETURN-POLICY",
"methodologyVersion": "1.0"
}Showing 14 of 16 fields.
Diagrams#
Calculation flow#
Evidence-to-adjustment calculation flow
flowchart LR
A["Versioned event evidence"] --> B["Select latest available revision"]
B --> C{"Cancelled?"}
C -->|Yes| X["Stop with diagnostic"]
C -->|No| D["Validate ex-date and official-close anchor"]
D --> E["Apply preceding same-day action bases"]
E --> F["Convert FX and gross or net cash"]
F --> G{"Named policy says special?"}
G -->|No| H["Factor 1; ordinary treatment"]
G -->|Yes| I["Subtract cash and reject nonpositive result"]
I --> J["Factor, returns, and lineage"]
H --> J
Point-in-time revision lifecycle
stateDiagram-v2
[*] --> Announced
Announced --> Revised: later version becomes available
Announced --> Cancelled: cancellation becomes latest
Revised --> Revised: another version becomes available
Revised --> Cancelled: cancellation becomes latest
Announced --> Effective: asOf reaches exAt
Revised --> Effective: asOf reaches exAt
Effective --> Corrected: post-event revision is processed by policy
Cancelled --> [*]
Corrected --> [*]
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 - S&P Dow Jones Indices Equity Indices Policies & Practices
- R2 - FTSE Russell Corporate Actions and Events Guide for Market Capitalisation Weighted Indices
- R3 - FINRA Rule 11140, Transactions in Securities "Ex-Dividend," "Ex-Rights" or "Ex-Warrants"
- R4 - Costco Wholesale Corporation declares special cash dividend of $10 per share