Portfolio & Market Risk

Define Named Market Shocks Once, Replay Them Anywhere

The TeaVM Java program records one European call kernel, applies five named relative or additive market shocks, and replays a configurable spot ladder using common random numbers.

Base market
Spot ladderOptional
SimulationOptional
Java source
ScenarioDslRiskStudio.java

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

package com.nablatensor.examples.learn;

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

public final class ScenarioDslRiskStudio {
  private ScenarioDslRiskStudio() {}

  public static void main(String[] args) {
    EquityMarket base = EquityMarket.of()
        .spot(100)
        .strike(100)
        .vol(20 / 100.0)
        .rate(3 / 100.0)
        .maturity(1)
        .build();
    long paths = 200000L, seed = 42L;
    try (MonteCarlo<EquityMarket> mc = MonteCarlo.of(Products.europeanCall())
        .market(base)
        .steps(1)
        .fp64()
        .greeks()
        .on("cpu")
        .build()) {
      named(mc, "base", base, paths, seed, "no shocks");
      named(mc, "rally", base.withSpot(base.spot() * 1.10), paths, seed, "spot relative +10%");
      named(mc, "crash", base.withSpot(base.spot() * 0.80)
          .withVol(base.vol() + 0.05), paths, seed, "spot relative -20%, vol additive +5pt");
      named(mc, "rate hike", base.withRate(base.rate() + 0.01), paths, seed, "rate additive +1pt");
      named(mc, "crash + rate cut", base.withSpot(base.spot() * 0.80)
          .withVol(base.vol() + 0.05)
          .withRate(base.rate() - 0.0075), paths, seed, "spot -20%, vol +5pt, rate -0.75pt");
      int points = Math.max(1, Math.min(101, 9));
      double range = 25 / 100.0;
      for (int n = 0; n < points; n++) {
        double rel = points == 1 ? 0.0 : -range + 2.0 * range * n / (points - 1);
        EquityMarket m = base.withSpot(base.spot() * (1 + rel));
        Nabla.TypedValuation<EquityMarket> v = mc.run(m, paths, seed);
        System.out.println("LADDER|" + m.spot() + "|" + v.price() + "|" + v.greek(EquityMarket::spot));
      }
    }
  }

  private static void named(MonteCarlo<EquityMarket> mc, String name, EquityMarket m, long n, long seed,
      String shocks) {
    Nabla.TypedValuation<EquityMarket> v = mc.run(m, n, seed);
    System.out.println("NAMED|" + name + "|" + shocks + "|" + v.price() + "|" + v.greek(EquityMarket::spot));
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

Scenarios as versioned market-data transformations

A small scenario language makes shock definitions composable, readable and reusable across a book.

Core mechanism

Each named scenario is a set of relative or absolute transformations to named factors. A ladder composes related shocks while preserving the baseline, so a replay result has clear scenario lineage.

Practical workflow

Maintain a factor taxonomy, name scenarios according to intent, test composition rules, and persist the exact scenario definition with every risk result.

Key details

Declare shocks as data; the runner expands them onto setInput + replay of an already-compiled kernel — no re-record, no recompile.

The FRTB curvature charge is exactly this pattern: two RELATIVE shocks (±RW·x) per risk factor, re-priced on the compiled kernel — see the curvature showcase.

A named scenario should state both its baseline and its transformation: whether a shock is absolute or relative, which factor identifiers it affects, and how it composes with other shocks. That makes scenario P&L reproducible and prevents a label such as “severe stress” from hiding different implementations over time.

A ladder is particularly useful for sensitivity analysis because each rung changes one economic quantity by a documented amount. The resulting curve of P&L against shock size reveals non-linearity and helps distinguish a local Greek from a full stressed revaluation.

Scope and review point

A DSL prevents ambiguous implementation, not ambiguous economics. The choice and severity of shocks still require risk-owner approval.