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.CorrelationScenarioEnum;
import com.nablatensor.risk.NestedAggregation;
import com.nablatensor.risk.RiskClassEnum;
import com.nablatensor.risk.RiskFactor;
import com.nablatensor.risk.RiskMeasureEnum;
import com.nablatensor.risk.Sensitivities;
import java.util.HashSet;
import java.util.EnumMap;
import java.util.Map;
import java.util.Set;
public final class FrtbFullRiskStudio {
static final RiskClassEnum[] RC = RiskClassEnum.values();
static final Map<RiskClassEnum, Integer> LEVEL_SOURCE = new EnumMap<>(RiskClassEnum.class);
static {
LEVEL_SOURCE.put(RiskClassEnum.GIRR, 0);
LEVEL_SOURCE.put(RiskClassEnum.CSR_NON_SEC, 1);
LEVEL_SOURCE.put(RiskClassEnum.CSR_SEC, 1);
LEVEL_SOURCE.put(RiskClassEnum.CSR_SEC_CTP, 1);
LEVEL_SOURCE.put(RiskClassEnum.EQUITY, 2);
LEVEL_SOURCE.put(RiskClassEnum.COMMODITY, 3);
LEVEL_SOURCE.put(RiskClassEnum.FX, 4);
}
static final String[][] BUCKET = {
{
"USD", "EUR"
}, {
"1", "3"
}, {
"1", "2"
}, {
"1", "2"
}, {
"1", "5"
}, {
"1", "2"
}, {
"EURUSD", "USDJPY"
}
};
static final double[][] RW = {
{
.017, .017
}, {
.005, .05
}, {
.009, .02
}, {
.04, .07
}, {
.55, .30
}, {
.30, .40
}, {
.15, .15
}
}, RHO = {
{
.4, .4
}, {
.35, .35
}, {
.4, .4
}, {
.35, .35
}, {
.25, .25
}, {
.55, .55
}, {
1, 1
}
};
static final double[] GAMMA = {
.5, .4, .4, .4, .15, .2, .6
};
public static void main(String[] a) {
String[] id = {
"ASIAN-001", "ASIAN-HEDGE", "MACRO-HEDGE"
}, ns = {
"NS-OPTIONS", "NS-OPTIONS", "NS-MACRO"
};
double[] notional = {
12000000, 4500000, 8000000
};
int[] side = {
-1, 1, 1
};
double spx = 100, ois = 4.2 / 100.0, spread = 1.2 / 100.0, fx = 1.085, wti = 76.5, iv = 20 / 100.0;
long paths = 200000L, seed = 42L;
Set<String> nettingSets = new HashSet<>();
for (String x : ns) nettingSets.add(x);
System.out.println("BOOK|" + id.length + "|" + nettingSets.size());
double cvr = equityCurvature(notional[0], side[0], paths, seed);
Sensitivities.Builder b = Sensitivities.builder();
int factorIndex;
for (int ti = 0; ti < id.length; ti++) {
double scale = side[ti] * notional[ti] / 1.0e6;
factorIndex = 0;
for (int ci = 0; ci < RC.length; ci++) for (String bucket : BUCKET[ci]) {
double alt = ((factorIndex++ + ti) % 2 == 0) ? 1.0 : -0.55;
double level = level(RC[ci], spx, ois, spread, fx, wti);
String name = RC[ci] + "-FACTOR-" + bucket;
b.add(factor(RC[ci], RiskMeasureEnum.DELTA, bucket, name, 0), scale * level * alt);
b.add(factor(RC[ci], RiskMeasureEnum.VEGA, bucket, name, 1), scale * iv * (1 + ti * .1));
b.add(factor(RC[ci], RiskMeasureEnum.CURVATURE, bucket, name, 0), Math.abs(scale) * .02 * alt);
}
}
b.add(RiskFactor.equityDelta("5", id[0])
.asCurvature(), cvr);
Sensitivities all = b.build();
double sbm = 0;
for (int ci = 0; ci < RC.length; ci++) {
double d = charge(all, ci, RiskMeasureEnum.DELTA), v = charge(all, ci, RiskMeasureEnum.VEGA),
c = charge(all, ci, RiskMeasureEnum.CURVATURE);
System.out.println("CLASS|" + RC[ci] + "|" + d + "|" + v + "|" + c + "|" + (d + v + c));
sbm += d + v + c;
}
double drc = drc(), drcHedged = drcHedged(), rraoOther = Math.abs(notional[0]) / 1e6 * .001,
rraoExotic = 2.0 * .01, rrao = rraoOther + rraoExotic, total = sbm + drc + rrao;
System.out.println("TOTAL|" + sbm + "|" + drc + "|" + drcHedged + "|" + rraoExotic + "|" + rraoOther
+ "|" + total);
}
static RiskFactor factor(RiskClassEnum rc, RiskMeasureEnum m, String bucket, String name, double tenor) {
return RiskFactor.of()
.riskClass(rc)
.measure(m)
.bucket(bucket)
.name(name)
.tenor(tenor)
.tenor2(0)
.build();
}
static double level(RiskClassEnum rc, double spx, double ois, double spread, double fx, double wti) {
int source = LEVEL_SOURCE.get(rc);
double[] levels = {
ois, spread, spx / 100, wti / 100, fx
};
return levels[source];
}
static int bucketIndex(int c, String b) {
for (int i = 0; i < BUCKET[c].length; i++) if (BUCKET[c][i].equals(b)) return i;
return 0;
}
static double charge(Sensitivities all, int ci, RiskMeasureEnum measure) {
Sensitivities slice = all.ofClass(RC[ci])
.ofMeasure(measure);
double best = 0;
for (CorrelationScenarioEnum sc : CorrelationScenarioEnum.values()) {
final int c = ci;
NestedAggregation.WithinBucketCorrelation rho = (x, y) -> sc.apply(RHO[c][bucketIndex(c, x.bucket())]);
NestedAggregation.AcrossBucketCorrelation gamma = (x, y) -> x.equals(y) ? 1.0 : sc.apply(GAMMA[c]);
NestedAggregation agg = measure == RiskMeasureEnum.CURVATURE ? NestedAggregation.curvature(rho,
gamma) : NestedAggregation.delta(f -> measure == RiskMeasureEnum.DELTA ? RW[c][bucketIndex(c,
f.bucket())] : 1.0, rho, gamma);
best = Math.max(best, agg.aggregate(slice)
.total());
}
return best;
}
static double drc() {
double longs = 4.4, shorts = .2, wl = 2.4 * .03 + 2 * .005, ws = .2 * .15, hbr = longs / (longs
+ shorts);
return Math.max(wl - hbr * ws, 0);
}
static double drcHedged() {
double wl = 2.4 * .03 + 2 * .005;
return Math.max(wl, 0);
}
static double equityCurvature(double notional, int side, long n, long seed) {
EquityMarket m = EquityMarket.of()
.spot(100)
.strike(100)
.vol(.2)
.rate(.03)
.maturity(1)
.build();
double units = Math.abs(notional) / 100.0 / 1.0e6, position = side;
try (MonteCarlo<EquityMarket> greek = MonteCarlo.of(Products.asianCall())
.market(m)
.steps(60)
.fp64()
.greeks()
.on("cpu")
.build(); MonteCarlo<EquityMarket> price = MonteCarlo.of(Products.asianCall())
.market(m)
.steps(60)
.fp64()
.priceOnly()
.on("cpu")
.build()) {
double base = position * units * price.run(n, seed)
.price(), delta = position * units * greek.run(n, seed)
.greek(EquityMarket::spot);
EquityMarket up = EquityMarket.of()
.spot(130)
.strike(100)
.vol(.2)
.rate(.03)
.maturity(1)
.build(), down = EquityMarket.of()
.spot(70)
.strike(100)
.vol(.2)
.rate(.03)
.maturity(1)
.build();
double pu = position * units * price.run(up, n, seed)
.price(), pd = position * units * price.run(down, n, seed)
.price(), shock = 30;
return -Math.min(pu - base - shock * delta, pd - base + shock * delta);
}
}
}