Regulatory Capital

Run a Supervisory Stress Scenario Without Re-Recording the Book

TeaVM Java full-revalues a long call / short put book across the existing three macro scenarios and four horizons. Both legs use the same seed at each grid node; the call delta is read from the replay that establishes the worst node.

Book
Market data
SimulationOptional

12 scenario/horizon cells, two leg prices per cell, plus four horizon baselines.

Java source
StressTestingRiskStudio.java

This exact source runs in TeaVM. Form changes update its Java literals and reset manual edits.

import com.nablatensor.engine.Nabla;
import com.nablatensor.quant.EquityMarket;
import com.nablatensor.quant.MonteCarlo;
import com.nablatensor.quant.Products;

public final class StressTestingRiskStudio {
  static final String[] MACRO = {
    "baseline", "adverse", "severely adverse"
  }, HORIZON = {
    "Q0", "Q1", "Q2", "Q3"
  };
  static final double[] SPOT_SHOCK = {
    0, -0.2, -0.4
  }, VOL_SHOCK = {
    0, 0.05, 0.15
  }, RATE_SHOCK = {
    0, -0.0075, -0.015
  }, TIME_SHOCK = {
    0, -0.25, -0.5, -0.75
  };
  public static void main(String[] a) {
    double s0 = 100, k = 100, v0 = 20 / 100.0, r0 = 3 / 100.0, t0 = 1;
    double callUnits = 5000000 / s0, putUnits = 3000000 / s0;
    long paths = 100000L, seed = 42L;
    EquityMarket base = market(s0, k, v0, r0, t0);
    try (MonteCarlo<EquityMarket> call = MonteCarlo.of(Products.europeanCall())
        .market(base)
        .steps(1)
        .fp64()
        .priceOnly()
        .on("cpu")
        .build(); MonteCarlo<EquityMarket> put = MonteCarlo.of(Products.europeanPut())
        .market(base)
        .steps(1)
        .fp64()
        .priceOnly()
        .on("cpu")
        .build(); MonteCarlo<EquityMarket> callGreek = MonteCarlo.of(Products.europeanCall())
        .market(base)
        .steps(1)
        .fp64()
        .greeks()
        .on("cpu")
        .build()) {
      double[] basePv = new double[4];
      for (int h = 0; h < 4; h++) {
        EquityMarket m = shocked(s0, k, v0, r0, t0, 0, h);
        basePv[h] = callUnits * call.run(m, paths, seed)
            .price() - putUnits * put.run(m, paths, seed)
            .price();
      }
      double worst = Double.POSITIVE_INFINITY, worstDelta = 0;
      int wi = 0, wh = 0;
      for (int x = 0; x < 3; x++) for (int h = 0; h < 4; h++) {
        EquityMarket m = shocked(s0, k, v0, r0, t0, x, h);
        double pv = callUnits * call.run(m, paths, seed)
            .price() - putUnits * put.run(m, paths, seed)
            .price();
        double loss = pv - basePv[h];
        System.out.println("GRID|" + MACRO[x] + "|" + HORIZON[h] + "|" + loss);
        if (loss < worst) {
          worst = loss;
          wi = x;
          wh = h;
          worstDelta = callGreek.run(m, paths, seed)
              .greek(EquityMarket::spot);
        }
      }
      System.out.println("WORST|" + MACRO[wi] + "|" + HORIZON[wh] + "|" + worst + "|" + worstDelta);
    }
  }
  static EquityMarket market(double s, double k, double v, double r, double t) {
    return EquityMarket.of()
        .spot(s)
        .strike(k)
        .vol(v)
        .rate(r)
        .maturity(t)
        .build();
  }
  static EquityMarket shocked(double s, double k, double v, double r, double t, int x, int h) {
    return market(s * (1 + SPOT_SHOCK[x]), k, Math.max(0.001, v + VOL_SHOCK[x]), r + RATE_SHOCK[x],
        Math.max(0.01, t + TIME_SHOCK[h]));
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

Scenario loss is a valuation question

A stress scenario becomes useful only after its narrative is converted into complete, internally consistent market-data shocks.

Core mechanism

The recorded portfolio is replayed under each named shock set, producing comparable baseline and stressed values. The difference is scenario P&amp;L, which can be decomposed by position or risk factor when the input mapping is retained.

Practical workflow

Define the scenario narrative, translate it into curves, spreads, FX, volatility and correlation shocks, assess plausibility and coverage, and store the versioned scenario definition alongside results.

Key details

Analysis note — where the heaviest computation in supervisory stress testing sits and whether NablaTensor helps. Not committed scope. Date: 2026-09-02. Verdict: Strong fit (headline) — the canonical many-scenario, many-horizon full revaluation and the workload behind NablaTensor's scenario-DSL story; NablaTensor accelerates the market-risk / revaluation slice, not the credit / PPNR models. Calculators, not sign-off. This note describes where the computation sits and what NablaTensor could compute. Model validation, parameter attestation and regulatory submission stay with the user.

Regulator-run exercises that project capital ratios under severe-but-plausible macro scenarios; results feed capital buffers and distribution constraints.

This is the heaviest total-FLOP workload of any regime covered in these notes. The Fed transparency proposal adds a second copy: banks build internal replicas of the supervisory models and run them alongside their own.

The bottleneck is the full-portfolio revaluation replicated across the scenario × horizon grid — for market risk, CCR shocks and NII paths.

Not a standalone phase in the current 1–5 roadmap — it is a horizontal capability that the FRTB, CVA and IRRBB work all feed, and the lowest-priority coverage item. It reuses com.nablatensor.scenario.* and the adjoint engine directly; the deliverable is a scenario / horizon DSL and a results grid, not a new regulatory calculator.

Scope and review point

A fast revaluation does not make a scenario supervisory, comprehensive or plausible. Those are risk-management and governance judgments.