This class abstracts out the calculation of risk for a credit portfolio. This class abstracts out the calculation of risk for a credit portfolio. It contains calculateCreditRiskMonteCarlo(...) method annotated with @Gridify(...) annotation which means that execution will be split across multiple nodes.
Full Source Code
CreditRiskManager.java
package org.gridgain.examples.montecarlo.gigaspaces; import java.util.*; import org.gridgain.grid.gridify.*; import com.j_spaces.core.client.*; import com.j_spaces.map.*; public class CreditRiskManager { /** * Default randomizer with normal distribution. * Note that since every JVM on the grid will have its own random * generator (independently initialized) the Monte-Carlo simulation * will be slightly skewed when performed on the grid due to skewed * normal distribution of the sub-jobs comparing to execution on the * local node only with single random generator. Real-life applications * may want to provide its own implementation of distributed random * generator. */ private static Random rndGen = new Random(); /** * Calculates credit risk for a given credit portfolio. This calculation uses * Monte-Carlo Simulation to produce risk value. * <p> * Note that this class generally represents a business logic and the entire * grid enabling occurs in one line of annotation added to this method: * <pre> * Gridify(taskClass = CreditRiskGridTask.class) * </pre> * Note also that this annotation could have been added externally via XML * file leaving this file completely untouched - yet still fully grid enabled. * * @param spaceMapName Name of the GigaSpaces map. * @param mapKey Portfolio key inside the GigaSpaces map. * @param horizon Forecast horizon (in days). * @param iters Number of Monte-Carlo iterations. * @param percentile Cutoff level. * @return Credit risk value, i.e. the minimal amount that creditor has to * have available to cover possible defaults. * @throws FinderException Thrown in case of any error with GigaSpaces. */ @Gridify(taskClass = CreditRiskGridTask.class) public double calculateCreditRiskMonteCarlo(String spaceMapName, String mapKey, int horizon, int iters, double percentile) throws FinderException { IMap mapSpace = (IMap)CacheFinder.find(spaceMapName); Credit[] portfolio = (Credit[]) mapSpace.get(mapKey); System.out.println(">>> Calculating credit risk for portfolio [size=" + portfolio.length + ", horizon=" + horizon + ", percentile=" + percentile + ", iterations=" + iters + "] <<<"); double[] losses = calculateLosses(portfolio, horizon, iters); Arrays.sort(losses); double[] lossProbs = new double[losses.length]; // Count variational numbers. // Every next one either has the same value or previous one plus probability of loss. for (int i = 0; i < losses.length; i++) { if (i == 0) { // First time it's just a probability of first value. lossProbs[i] = getLossProbability(losses, i); } else if (losses[i] != losses[i - 1]) { // Probability of this loss plus previous one. lossProbs[i] = getLossProbability(losses, i) + lossProbs[i - 1]; } else { // The same loss the same probability. lossProbs[i] = lossProbs[i - 1]; } } // Count percentile. double crdRisk = 0; for (int i = 0; i < lossProbs.length; i++) { if (lossProbs[i] > percentile) { crdRisk = losses[i - 1]; break; } } return crdRisk; } /** * Calculates losses for the given credit portfolio using Monte-Carlo Simulation. * Simulates probability of default only. * * @param portfolio Credit portfolio. * @param horizon Forecast horizon. * @param iters Number of Monte-Carlo iterations. * @return Losses array simulated by Monte Carlo method. */ private double[] calculateLosses(Credit[] portfolio, int horizon, int iters) { double[] losses = new double[iters]; // Count losses using Monte-Carlo method. We generate random probability of default, // if it exceeds certain credit default value we count losses - otherwise count income. for (int i = 0; i < iters; i++) { for (Credit crd : portfolio) { int remDays = Math.min(crd.getRemainingTerm(), horizon); if (rndGen.nextDouble() >= 1 - crd.getDefaultProbability(remDays)) { // (1 + 'r' * min(H, W) / 365) * S. // Where W is a horizon, H is a remaining crediting term, 'r' is an annual credit rate, // S is a remaining credit amount. losses[i] += (1 + crd.getAnnualRate() * Math.min(horizon, crd.getRemainingTerm()) / 365) * crd.getRemainingAmount(); } else { // - 'r' * min(H,W) / 365 * S // Where W is a horizon, H is a remaining crediting term, 'r' is a annual credit rate, // S is a remaining credit amount. losses[i] -= crd.getAnnualRate() * Math.min(horizon, crd.getRemainingTerm()) / 365 * crd.getRemainingAmount(); } } } return losses; } /** * Calculates probability of certain loss in array of losses. * * @param losses Array of losses. * @param i Index of certain loss in array. * @return Probability of loss with given index. */ private double getLossProbability(double[] losses, int i) { double count = 0; double loss = losses[i]; for (double tmp : losses) { if (loss == tmp) { count++; } } return count / losses.length; } }
