src/lib/carry/__tests__/forwardFunding.test.ts

39 lines
import { describe, expect, it } from "vitest";
import { initialTable, twoWay } from "../../grid/rowModel";
import { DEFAULT_ALL_IN, SX5E_MARKET as m, SX5E_TRF_RUN } from "../../market/sx5e";
import { settlementFraction } from "../../pricing";
import { curveSpread, forwardOnCurve, type CurvePoint } from "../carry";

describe("monitor forward funding = the pricer's Forward Funding (carry-model terms)", () => {
  const rows = initialTable(m, SX5E_TRF_RUN.map((q) => ({ expiry: q.expiry, trf: twoWay(q.bid, q.offer) })), DEFAULT_ALL_IN);

  it("matches the pricer's Forward Funding marks for adjacent tenors", () => {
    for (let i = 1; i < rows.length; i++) {
      const horizon = rows[i - 1].expiry.date; // near expiry
      const curve: CurvePoint[] = rows.map((r) => ({
        label: r.expiry.label,
        delta: settlementFraction(m.valuationDate, r.expiry.date),
        deltaAfter: r.expiry.date > horizon ? settlementFraction(horizon, r.expiry.date) : 0,
        spread: r.fund.mark,
      }));
      const fwd = forwardOnCurve(curve, rows[i - 1].expiry.label, rows[i].expiry.label);
      expect(fwd.today).toBeCloseTo(rows[i].fwdFund.mark, 8);
      // at the near expiry the forward period has started: it is the curve at the far leg's remaining maturity
      expect(fwd.atHorizon).toBeCloseTo(curveSpread(curve, curve[i].deltaAfter), 12);
    }
  });

  it("is not the TRF forward: the dividend pass-through is stripped out", () => {
    const toCurve = (col: "trf" | "fund"): CurvePoint[] =>
      rows.map((r) => ({
        label: r.expiry.label,
        delta: settlementFraction(m.valuationDate, r.expiry.date),
        deltaAfter: 0,
        spread: r[col].mark,
      }));
    const funding = forwardOnCurve(toCurve("fund"), "Dec27", "Dec28").today;
    const trf = forwardOnCurve(toCurve("trf"), "Dec27", "Dec28").today;
    expect(trf - funding).toBeGreaterThan(50); // ≈ 98.4 vs ≈ 18.1 at the defaults
  });
});