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),
};
}