import type { ForwardArgs } from "./types";
/** Sum of gross dividends going ex in (0, t], each carried from pay date to expiry at €STR (no settlement lag). */
export function carriedGrossDividends(a: ForwardArgs): number {
let sum = 0;
for (const d of a.dividends) {
if (d.t > 0 && d.t <= a.t) sum += d.gross * Math.exp(a.rate * (a.t - d.t));
}
return sum;
}
/** Undiscounted gross dividends going ex in (0, t]. */
export function cumulativeGrossDividends(a: Pick<ForwardArgs, "dividends" | "t">): number {
let sum = 0;
for (const d of a.dividends) if (d.t > 0 && d.t <= a.t) sum += d.gross;
return sum;
}
/** Dividend multiplier: `divScale` for dividends after `divScaleFrom`, 1 for earlier (pre-scaled) ones. */
export const divFactor = (a: ForwardArgs, exTime: number) =>
exTime > (a.divScaleFrom ?? -Infinity) ? a.divScale : 1;
/** Gross dividends going ex in (0, t], with the scaling curve applied. */
export function scaledCumulativeDividends(a: ForwardArgs): number {
let sum = 0;
for (const d of a.dividends) if (d.t > 0 && d.t <= a.t) sum += d.gross * divFactor(a, d.t);
return sum;
}
/**
* Net dividends going ex in (0, exCutoff] (pay date = ex date), each received on its pay date
* and carried to `settle` at €STR:
*
* FV = allIn · Σ kᵢ·Dᵢ·e^{€STR·(settle − payᵢ)}
*
* At €STR, not €STR + s: once paid, a dividend is cash, reinvested at the cash rate.
*/
export function carriedNetDividends(a: ForwardArgs, exCutoff = a.t, settle = a.settle?.expiry ?? a.t): number {
let sum = 0;
for (const d of a.dividends) {
if (d.t > 0 && d.t <= exCutoff) sum += divFactor(a, d.t) * d.gross * Math.exp(a.rate * (settle - d.t));
}
return a.allIn * sum;
}
/**
* Cost-of-carry forward, continuous compounding:
*
* F = S · e^{R·(T_settle − t_settle)} − FV(net divs), R = €STR + s
*
* The cash index is funded at R from spot settlement (t + 2 weekdays) to the expiry's
* settlement (T + 2 weekdays); dividends going ex in (t, T] (pay = ex) are carried from
* their pay date to the expiry's settlement at €STR.
* Without `settle` both lags are zero and this is S·e^{Rt} − allIn·k·Σ Dᵢ·e^{€STR(t−tᵢ)}.
*/
export function priceForward(a: ForwardArgs): number {
const R = a.rate + a.fundingSpread;
const carry = (a.settle?.expiry ?? a.t) - (a.settle?.spot ?? 0);
return a.spot * Math.exp(R * carry) - carriedNetDividends(a);
}