src/lib/pricing/implied.ts

33 lines
import { brent, expandBracket } from "./brent";
import type { ForwardArgs, Pricer, SolvableKey } from "./types";

/** Starting brackets; widened automatically if the root lies outside. */
export const DEFAULT_BRACKETS: Record<SolvableKey, [number, number]> = {
  spot: [1, 20_000],
  rate: [-0.1, 0.2],
  fundingSpread: [-0.1, 0.1],
  allIn: [0, 1.5],
  divScale: [0, 3],
  eqlSpread: [-0.1, 0.1],
};

/**
 * Generic inverse solver: finds x such that pricer({...base, [key]: x}) = target.
 *
 *   implied(fairSyntheticPrice, "fundingSpread", -45.5, args)  // funding from a synthetic
 *   implied(fairTRFSpread,      "fundingSpread", 62.5,  args)  // funding from a TRF
 *   implied(fairSyntheticPrice, "allIn",         -45.5, args)  // all-in from a synthetic
 */
export function implied(
  pricer: Pricer,
  key: SolvableKey,
  target: number,
  base: ForwardArgs,
  opts: { bracket?: [number, number]; tol?: number } = {},
): number {
  const f = (x: number) => pricer({ ...base, [key]: x }) - target;
  const [lo, hi] = opts.bracket ?? DEFAULT_BRACKETS[key];
  const [a, b] = expandBracket(f, lo, hi);
  return brent(f, a, b, opts.tol ?? 1e-14);
}