fintech-algorithms
Using a coding agent? Give it the skill: npx skills add IslamBaraka90/Fintech-Algorithms-Library What it does →

Special-Dividend Adjustment

Preserve Return Meaning Across the Ex-Date

Install and import#

bash
npm install fintech-algorithms
ts
import { 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#

NameTypeNotes
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#

rawData
{
  "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#

Special-Dividend Adjustment — article hero
Special-Dividend Adjustment — failure guard
Special-Dividend Adjustment — worked example

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.

Read the article →

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

The rest of the Complex Distributions family#