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

Rights-Issue Bonus-Factor Adjustment

Install and import#

bash
npm install fintech-algorithms
ts
import { rightsIssueBonusFactorAdjustment } from "fintech-algorithms/earnings-and-per-share-analytics/earnings-and-share-foundations/rights-issue-bonus-factor-adjustment";

Signature#

rightsIssueBonusFactorAdjustment(input)

Extracts the bonus element of a rights issue by computing the theoretical ex-rights price and the market-to-TERP adjustment factor, then restates prior-period weighted-average shares and basic EPS with it. All arithmetic runs in 50-significant-digit decimal with half-even rounding and the figures come back as exact decimal strings. A contract failure is rethrown as an Error whose message begins EPS calculation failed: .

Parameters#

NameTypeNotes
input{ events: Array<{ event_id, effective_or_exercise_date, existing_shares_per_block, new_shares_per_block, cum_rights_fair_value_per_share, subscription_price_per_share, offered_to_all_existing_shareholders, event_is_effective }>, periods: Array<{ period_id, basis_date, basis_is_uniform, earnings_available_to_ordinary_shareholders, weighted_average_ordinary_shares }> }events and periods are both required and must be non-empty arrays. Each event needs existing_shares_per_block and new_shares_per_block as positive integer strings, an effective_or_exercise_date in YYYY-MM-DD form, a cum_rights_fair_value_per_share above zero, a subscription_price_per_share from zero up to that fair value, and both offered_to_all_existing_shareholders and event_is_effective set to true. Unlike the bonus-issue topic, event ids and dates are not required to be unique or ordered. Each period needs a basis_date, basis_is_uniform set to true, decimal earnings_available_to_ordinary_shareholders and a strictly positive weighted_average_ordinary_shares. Nothing is defaulted.

Returns#

{ topic_id, state, events, periods }

state is always calculated. events gives one row per input event with event_id, terp and the reduced factor as factor_numerator and factor_denominator. periods gives period_id, applied_event_ids, factor_numerator, factor_denominator, restated_shares and restated_basic_eps; a period picks up only the events dated strictly after its basis_date. Unlike the bonus-issue topic, no earnings or pre-restatement columns are emitted.

Errors#

  • When subscription_price_per_share exceeds cum_rights_fair_value_per_share or is negative, or the fair value is not above zero — throws Error
  • When offered_to_all_existing_shareholders or event_is_effective is not true, a per-block share count is not a positive integer string, a date is not a real YYYY-MM-DD value, weighted_average_ordinary_shares is not positive, or basis_is_uniform is not true — throws Error

Complexity: time O(e * p) for e events and p periods, space O(e + p).

Worked example#

executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.

Input#

input
{
  "events": [
    {
      "event_id": "SYN-RIGHTS-1",
      "effective_or_exercise_date": "2025-06-01",
      "existing_shares_per_block": "4",
      "new_shares_per_block": "1",
      "cum_rights_fair_value_per_share": "12.50",
      "subscription_price_per_share": "8.00",
      "offered_to_all_existing_shareholders": true,
      "event_is_effective": true
    }
  ],
  "periods": [
    {
      "period_id": "SYN-2024",
      "basis_date": "2024-12-31",
      "basis_is_uniform": true,
      "earnings_available_to_ordinary_shareholders": "18000000",
      "weighted_average_ordinary_shares": "9000000"
    },
    {
      "period_id": "SYN-CURRENT",
      "basis_date": "2025-06-01",
      "basis_is_uniform": true,
      "earnings_available_to_ordinary_shareholders": "9500000",
      "weighted_average_ordinary_shares": "9700000"
    }
  ]
}

Call#

rightsIssueBonusFactorAdjustment(input)

Returns#

object with 4 fields: topic_id, state, events, periods

{
  "topic_id": "D46-F01-A07",
  "state": "calculated",
  "events": [
    {
      "event_id": "SYN-RIGHTS-1",
      "terp": "11.6",
      "factor_numerator": "125",
      "factor_denominator": "116"
    }
  ],
  "periods": [
    {
      "period_id": "SYN-2024",
      "applied_event_ids": ["SYN-RIGHTS-1"],
      "factor_numerator": "125",
      "factor_denominator": "116",
      "restated_shares": "9698275.8620689655172413793103448275862068965517241",
      "restated_basic_eps": "1.856"
    },
    {
      "period_id": "SYN-CURRENT",
      "applied_event_ids": [],
      "factor_numerator": "1",
      "factor_denominator": "1",
      "restated_shares": "9700000",
      "restated_basic_eps": "0.97938144329896907216494845360824742268041237113402"
    }
  ]
}

Diagrams#

Rights-Issue Bonus-Factor Adjustment — terp value bridge

Calculation flow#

Rights-issue bonus-factor flow
flowchart LR
  A["Validated rights event"] --> B{"Offered to all existing shareholders?"}
  B -- "No" --> X["Reject from canonical method"]
  B -- "Yes" --> C{"Non-time contingency resolved?"}
  C -- "No" --> Y["Wait; do not adjust"]
  C -- "Yes / none" --> D["Validate price date, source, currency, and scale"]
  D --> E["TERP = (n × M + r × S) ÷ (n + r)"]
  E --> F{"Subscription price S < fair value M?"}
  F -- "No" --> G["No bonus element; factor = 1"]
  F -- "Yes" --> H["Bonus factor = M ÷ TERP"]
  H --> I["Apply only to eligible pre-rights basis"]
  G --> I
  I --> J["Preserve earnings and recalculate historical EPS"]
  A --> K["Actual new shares"]
  K --> L["Time-weight from issue or exercise date"]

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#

  • IAS 33 Earnings per Share
  • Statement No. 128, Earnings per Share
  • Filed rights-issue restatement example
  • SEC staff comment on factor direction
  • Research limits

The rest of the Earnings and Share Foundations family#