Regulatory Capital

Compute FRTB Curvature Capital

Java performs an adjoint delta valuation and three same-seed arithmetic Asian call valuations, then applies the prescribed 30% equity shock and curvature residual.

Position
Market data
SimulationOptional

The browser uses 20,000 scenarios by default; common random numbers are used for base, up and down runs.

Java source
FrtbCurvatureRiskStudio.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;
import com.nablatensor.risk.NestedAggregation;
import com.nablatensor.risk.RiskFactor;
import com.nablatensor.risk.Sensitivities;

public final class FrtbCurvatureRiskStudio {
  private FrtbCurvatureRiskStudio() {}

  public static void main(String[] args) {
    EquityMarket m = EquityMarket.of()
        .spot(100)
        .strike(100)
        .vol(20 / 100.0)
        .rate(3 / 100.0)
        .maturity(1)
        .build();
    int steps = 64;
    long scenarios = 20000L, seed = 42L;
    double position = -1.0, units = 1000000 / m.spot(), shock = 0.30 * m.spot();
    try (MonteCarlo<EquityMarket> greek = MonteCarlo.of(Products.asianCall())
        .market(m)
        .steps(steps)
        .fp64()
        .greeks()
        .on("cpu")
        .build(); MonteCarlo<EquityMarket> pricer = MonteCarlo.of(Products.asianCall())
        .market(m)
        .steps(steps)
        .fp64()
        .on("cpu")
        .build()) {
      Nabla.TypedValuation<EquityMarket> gv = greek.run(scenarios, seed);
      Nabla.TypedValuation<EquityMarket> base = pricer.run(scenarios, seed);
      EquityMarket upM = EquityMarket.of()
          .spot(m.spot() * 1.30)
          .strike(m.strike())
          .vol(m.vol())
          .rate(m.rate())
          .maturity(m.maturity())
          .build();
      EquityMarket downM = EquityMarket.of()
          .spot(m.spot() * 0.70)
          .strike(m.strike())
          .vol(m.vol())
          .rate(m.rate())
          .maturity(m.maturity())
          .build();
      Nabla.TypedValuation<EquityMarket> up = pricer.run(upM, scenarios, seed);
      Nabla.TypedValuation<EquityMarket> down = pricer.run(downM, scenarios, seed);
      double pv0 = position * units * base.price(), pvu = position * units * up.price(), pvd = position * units * down.price();
      double delta = position * units * gv.greek(EquityMarket::spot);
      double cvr = -Math.min(pvu - pv0 - shock * delta, pvd - pv0 + shock * delta);
      Sensitivities risk = Sensitivities.builder()
          .add(RiskFactor.equityDelta("5", "ASIAN-CALL")
          .asCurvature(), cvr)
          .build();
      double charge = NestedAggregation.curvature((a, b) -> a.name()
          .equals(b.name()) && a.bucket()
          .equals(b.bucket()) ? 1.0 : 0.25, (a, b) -> a.equals(b) ? 1.0 : 0.15)
          .aggregate(risk)
          .total();
      System.out.println("RESULT|" + pv0 + "|" + pvu + "|" + pvd + "|" + delta + "|" + shock + "|"
          + cvr + "|" + charge);
    }
  }
}
TeaVM compiles and runs the Java source above in this browser.
Regulatory context · FRTB Standardised Approach

Where this curvature calculation fits

This interactive calculation is a deliberately small, one-factor illustration of the curvature part of the Fundamental Review of the Trading Book (FRTB) Standardised Approach. It demonstrates the expensive part of the measure — shocked full repricing — but it is not a regulatory capital calculation or a sign-off tool.

The full capital stack

FRTB standardised capital is the sum of three independently calculated components. Diversification is recognised inside the sensitivities-based method, but not between these three components.

FRTB SA own-funds requirement
  = SBM capital charge       delta + vega + curvature
  + DRC                      default / jump-to-default risk
  + RRAO                     residual-risk gross-notional add-on

This page covers one curvature risk factor only. DRC and RRAO are intentionally outside the browser demo.

Why curvature needs repricing

Delta is a local first-order approximation. Curvature measures the remaining non-linear P&L after the supervisory up and down shocks, once the delta contribution has been removed. The shocks must therefore pass through the whole valuation, including the path-dependent Asian payoff used here.

up residual   = PV(up)   − PV(base) − shock × delta
down residual = PV(down) − PV(base) + shock × delta

CVR = adverse non-linear residual

The displayed sign convention is the one implemented by this teaching example; production reporting must follow the applicable rulebook and bank-wide P&L/sign conventions exactly.

What the demo actually does

  1. Records the base valuation and obtains the spot delta from an adjoint sweep.
  2. Reprices the same trade under prescribed relative spot-up and spot-down shocks.
  3. Uses common random numbers across base and shocked runs to reduce Monte-Carlo comparison noise.
  4. Removes the linear delta term from each shocked P&L and retains the adverse residual.
  5. Passes that single curvature risk value through the curvature aggregation used by the example.

For a real portfolio, the same pattern is repeated for every material curvature risk factor. That is why curvature is computationally different from delta and vega: it requires two shocked full revaluations per risk factor, not merely another component of a sensitivity vector.

How the production aggregation is structured

The Sensitivities-based Method (SBM) operates by risk class, measure and correlation scenario. It covers GIRR, credit-spread risk (three treatments), equity, commodity and FX. Within a bucket, weighted risk factors are aggregated using prescribed correlations; bucket results are then aggregated using prescribed cross-bucket correlations. Each risk class is evaluated under medium, high and low correlation scenarios, and the most conservative scenario is retained per class.

within bucket:  K_b = sqrt(max(0, own-risk + correlated cross terms))
across buckets: charge = sqrt(max(0, sum(K_b²) + correlated bucket terms))
SBM total:       sum over risk classes of max(high, medium, low)

Curvature uses its own asymmetric treatment of positive and negative curvature values in those formulas. The single equity-style spot factor on this page intentionally bypasses the risk-factor taxonomy, bucket tables, concentration thresholds and correlation matrices needed by a complete implementation.

Inputs a regulated run must govern

  • Current jurisdictional risk weights, correlations and liquidity horizons.
  • Risk-factor classification, bucketing, reporting currency and portfolio netting.
  • Market-data quality, valuation-model approval and independent price verification.
  • Scenario, parameter and result lineage suitable for audit and regulatory reporting.

How to read this example

  • Use it to inspect the relation between delta, two shocked PVs and the non-linear residual.
  • Change market inputs to see why the curvature charge is not a gamma times a fixed constant.
  • Read the Java source to follow the base valuation, shocked replays and curvature aggregation.
  • Do not infer a production capital number from the displayed result.