Price Exotic & Multi-Asset Trades

Price a Basket and Get a Full Cross-Greek Matrix

The Java source prices an equal-weight basket of three correlated assets. Spot deltas come from one adjoint sweep; the same recorded Java product is replayed with common random numbers for the cross-gamma matrix.

Assets
Correlation
Option
SimulationOptional

Cross-gamma uses 15 bump replays plus the base valuation, with common random numbers.

Java source
BasketOptionsRiskStudio.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.BasketMarket;
import com.nablatensor.quant.BasketOption;
import com.nablatensor.quant.OptionTypeEnum;

public final class BasketOptionsRiskStudio {
  private BasketOptionsRiskStudio() {}

  public static void main(String[] args) {
    BasketMarket m = BasketMarket.of()
        .s1(100)
        .s2(100)
        .s3(100)
        .v1(22 / 100.0)
        .v2(18 / 100.0)
        .v3(25 / 100.0)
        .rate(3 / 100.0)
        .build();
    double strike = 100, maturity = 1;
    double[] weights = {
      1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0
    };
    double[][] corr = {
      {
        1.0, 0.4, 0.2
      }, {
        0.4, 1.0, 0.3
      }, {
        0.2, 0.3, 1.0
      }
    };
    int steps = 12;
    long paths = 15000L, seed = 42L;
    try (Nabla.TypedPricer<BasketMarket> p = Nabla.model(m, BasketOption.option(OptionTypeEnum.CALL,
        weights, strike, corr, maturity, steps))
        .fp64()
        .greeks()
        .on("cpu")
        .build()) {
      Nabla.TypedValuation<BasketMarket> base = p.value()
          .with(m)
          .scenarios(paths)
          .seed(seed)
          .run();
      BasketMarket g = base.greeks();
      System.out.println("RESULT|" + base.price() + "|" + g.s1() + "|" + g.s2() + "|" + g.s3());
      double[] s = {
        m.s1(), m.s2(), m.s3()
      }, h = {
        s[0] * 0.01, s[1] * 0.01, s[2] * 0.01
      };
      double[][] gamma = new double[3][3];
      for (int a = 0; a < 3; a++) {
        double[] up = s.clone(), dn = s.clone();
        up[a] += h[a];
        dn[a] -= h[a];
        gamma[a][a] = (price(p, m, up[0], up[1], up[2], paths, seed) - 2.0 * base.price() + price(p,
            m, dn[0], dn[1], dn[2], paths, seed)) / (h[a] * h[a]);
      }
      for (int a = 0; a < 3; a++) for (int b = a + 1; b < 3; b++) {
        double[] pp = s.clone(), pm = s.clone(), mp = s.clone(), mm = s.clone();
        pp[a] += h[a];
        pp[b] += h[b];
        pm[a] += h[a];
        pm[b] -= h[b];
        mp[a] -= h[a];
        mp[b] += h[b];
        mm[a] -= h[a];
        mm[b] -= h[b];
        gamma[a][b] = (price(p, m, pp[0], pp[1], pp[2], paths, seed) - price(p, m, pm[0], pm[1],
            pm[2], paths, seed) - price(p, m, mp[0], mp[1], mp[2], paths, seed) + price(p, m, mm[0],
            mm[1], mm[2], paths, seed)) / (4 * h[a] * h[b]);
        gamma[b][a] = gamma[a][b];
      }
      for (int a = 0; a < 3; a++) System.out.println("GAMMA|" + a + "|" + gamma[a][0] + "|" + gamma[a][1]
          + "|" + gamma[a][2]);
    }
  }

  private static double price(Nabla.TypedPricer<BasketMarket> p, BasketMarket original, double s1,
      double s2, double s3, long paths, long seed) {
    BasketMarket bumped = BasketMarket.of()
        .s1(s1)
        .s2(s2)
        .s3(s3)
        .v1(original.v1())
        .v2(original.v2())
        .v3(original.v3())
        .rate(original.rate())
        .build();
    return p.value()
        .with(bumped)
        .scenarios(paths)
        .seed(seed)
        .run()
        .price();
  }
}
TeaVM compiles and runs the Java source above in this browser.
Implementation guide

Correlation turns single-asset risk into a matrix

A basket payoff depends jointly on several underlyings, so dependence assumptions and cross-sensitivities are part of the economic result.

Core mechanism

One recorded valuation obtains per-asset deltas. Repeated directional changes of the same tape reveal cross-gamma terms: how one asset's move changes another asset's delta.

Practical workflow

Calibrate marginal volatilities and correlations consistently, label all assets, examine matrix symmetry and stability, and separate model correlation risk from market spot risk.

Key details

*Keywords: heston monte carlo java, sabr monte carlo, hull-white one factor java, libor market model java, adjoint model parameter risk*

Phase 1 adds five model step blocks in nablatensor-quant. Each is a small class that reads its parameters from a typed market record, exposes a step(...) method, and provides a ready european(...) / product builder. Because the parameters are ADouble inputs, one adjoint sweep returns the full model parameter gradient — the sensitivities a calibration or risk-attribution loop consumes — next to the usual spot/rate Greeks.

ModelsTest checks, for every model, that the full adjoint parameter gradient agrees with a central bump-and-revalue on the same seed, plus a degenerate identity per model:

Heston's variance-parameter adjoints (v0, kappa, theta, xi) match a bump only to a few percent — full-truncation Euler's max(v, 0) floor is non-smooth on a measure-zero set; the spot / rate / strike / rho adjoints are exact to Monte-Carlo noise. This is a property of the scheme, documented on HestonModel.

Scope and review point

The browser matrix is a small illustrative portfolio. High-dimensional correlation modelling, calibration and hedging need additional controls.