Functional Weave
Code in Rust

invest.dividend-yield@1.0.1

impl/typescript.ts

1,891 bytes · the TypeScript implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { type Money, money } from "./money_amount.ts";  ← from money.amount ^1.0.0 · built alongside by fune
import { type DividendYield } from "./invest_dividend_yield_types.ts";

/** amount x 10000 / price, half-up; both 0 or more, price > 0. */
function basisPoints(amount: number, price: number): number {
  const n = BigInt(amount) * 10000n;
  const d = BigInt(price);
  let q = n / d;
  if (2n * (n - q * d) >= d) q += 1n;
  return Number(q);
}

/**
 * Trailing yield from the dividends paid in the last twelve months, and
 * forward yield from the latest regular dividend annualised, both over the
 * current price.
 */
export function dividendYield(
  price: Money,
  trailingDividends: readonly Money[],
  forwardDividend: Money,
  paymentsPerYear: number
): DividendYield {
  const currency = price.currency;
  if (!Number.isInteger(price.minor) || price.minor <= 0) {
    throw new RangeError(`price must be whole minor units greater than zero; received ${price.minor}`);
  }
  if (!Number.isInteger(paymentsPerYear) || paymentsPerYear < 1 || paymentsPerYear > 52) {
    throw new RangeError(`paymentsPerYear must be a whole number from 1 to 52; received ${paymentsPerYear}`);
  }
  let trailing = 0;
  for (const dividend of [...trailingDividends, forwardDividend]) {
    if (dividend.currency !== currency) throw new RangeError(`currency mismatch: ${currency} and ${dividend.currency}`);
    if (!Number.isInteger(dividend.minor) || dividend.minor < 0) {
      throw new RangeError(`dividends must be whole minor units, 0 or more; received ${dividend.minor}`);
    }
  }
  for (const dividend of trailingDividends) trailing += dividend.minor;
  const forward = forwardDividend.minor * paymentsPerYear;
  return {
    trailingAnnual: money(trailing, currency),
    forwardAnnual: money(forward, currency),
    trailingBasisPoints: basisPoints(trailing, price.minor),
    forwardBasisPoints: basisPoints(forward, price.minor),
  };
}