TwoStateMarkovChainFitter { public LeastSquareResultsWithTransform fit(final ForwardCurve forward, final List<Pair<double[], Double>> marketVols, final DoubleMatrix1D initialGuess) { ArgumentChecker.isTrue(initialGuess.getNumberOfElements() == TRANSFORMS.getNumberOfModelParameters(), "Number of elements in initial guess {} did not match the number of parameter transforms {}", initialGuess.getNumberOfElements(), TRANSFORMS.getNumberOfFittingParameters()); TRANSFORMS.transform(initialGuess); final int nMarketValues = marketVols.size(); double tminT = Double.POSITIVE_INFINITY; double tminK = Double.POSITIVE_INFINITY; double tmaxT = 0; double tmaxK = 0; for (int i = 0; i < nMarketValues; i++) { final double[] tk = marketVols.get(i).getFirst(); if (tk[0] > tmaxT) { tmaxT = tk[0]; } if (tk[0] < tminT) { tminT = tk[0]; } if (tk[1] > tmaxK) { tmaxK = tk[1]; } if (tk[1] < tminK) { tminK = tk[1]; } } final double minT = 0.6 * tminT; final double minK = 0.9 * tminK; final double maxT = 1.0 * tmaxT; final double maxK = 1.1 * tmaxK; final int tNodes = 20; final int xNodes = 100; final MeshingFunction timeMesh = new ExponentialMeshing(0, tmaxT, tNodes, 5.0); final MeshingFunction spaceMesh = new HyperbolicMeshing(0, 10.0 * forward.getForward(maxT), forward.getSpot(), xNodes, 0.01); final PDEGrid1D grid = new PDEGrid1D(timeMesh, spaceMesh); final Function1D<DoubleMatrix1D, DoubleMatrix1D> funcAppox = new Function1D<DoubleMatrix1D, DoubleMatrix1D>() { @SuppressWarnings("synthetic-access") @Override public DoubleMatrix1D evaluate(final DoubleMatrix1D x) { final DoubleMatrix1D y = TRANSFORMS.inverseTransform(x); final double vol1 = y.getEntry(0); final double deltaVol = y.getEntry(1); final double lambda12 = y.getEntry(2); final double lambda21 = y.getEntry(3); final double p0 = y.getEntry(4); final double beta = y.getEntry(5); final double[] modVols = new double[nMarketValues]; for (int i = 0; i < nMarketValues; i++) { final double[] temp = marketVols.get(i).getFirst(); final double t = temp[0]; final double k = temp[1]; final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true); final BlackFunctionData data = new BlackFunctionData(forward.getForward(t), 1.0, 0.0); final MarkovChainApprox mca = new MarkovChainApprox(vol1, vol1 + deltaVol, lambda12, lambda21, p0, t); final double price = mca.priceCEV(data.getForward(), data.getDiscountFactor(), k, beta); try { modVols[i] = BLACK_IMPLIED_VOL.getImpliedVolatility(data, option, price); } catch (final Exception e) { modVols[i] = 0.0; } } return new DoubleMatrix1D(modVols); } }; final Function1D<DoubleMatrix1D, DoubleMatrix1D> func = new Function1D<DoubleMatrix1D, DoubleMatrix1D>() { @SuppressWarnings("synthetic-access") @Override public DoubleMatrix1D evaluate(final DoubleMatrix1D x) { final DoubleMatrix1D y = TRANSFORMS.inverseTransform(x); final double vol1 = y.getEntry(0); final double deltaVol = y.getEntry(1); final double lambda12 = y.getEntry(2); final double lambda21 = y.getEntry(3); final double p0 = y.getEntry(4); final double beta = y.getEntry(5); final TwoStateMarkovChainDataBundle chainData = new TwoStateMarkovChainDataBundle(vol1, vol1 + deltaVol, lambda12, lambda21, p0, beta, beta); final TwoStateMarkovChainPricer mc = new TwoStateMarkovChainPricer(forward, chainData); final PDEFullResults1D res = mc.solve(grid, _theta); final Map<DoublesPair, Double> data = PDEUtilityTools.priceToImpliedVol(forward, res, minT, maxT, minK, maxK, true); final Map<Double, Interpolator1DDataBundle> dataBundle = GRID_INTERPOLATOR2D.getDataBundle(data); final double[] modVols = new double[nMarketValues]; for (int i = 0; i < nMarketValues; i++) { final double[] temp = marketVols.get(i).getFirst(); final DoublesPair tk = DoublesPair.of(temp[0], temp[1]); try { modVols[i] = GRID_INTERPOLATOR2D.interpolate(dataBundle, tk); } catch (final Exception e) { s_logger.error(e.getMessage()); } } return new DoubleMatrix1D(modVols); } }; final double[] mrkVols = new double[nMarketValues]; final double[] sigma = new double[nMarketValues]; for (int i = 0; i < nMarketValues; i++) { mrkVols[i] = marketVols.get(i).getSecond(); sigma[i] = 0.01; } final NonLinearLeastSquare ls = new NonLinearLeastSquare(); LeastSquareResults solverRes = ls.solve(new DoubleMatrix1D(mrkVols), new DoubleMatrix1D(sigma), funcAppox, TRANSFORMS.transform(initialGuess)); solverRes = ls.solve(new DoubleMatrix1D(mrkVols), new DoubleMatrix1D(sigma), func, solverRes.getFitParameters()); return new LeastSquareResultsWithTransform(solverRes, TRANSFORMS); } TwoStateMarkovChainFitter();  TwoStateMarkovChainFitter(final double theta); LeastSquareResultsWithTransform fit(final ForwardCurve forward, final List<Pair<double[], Double>> marketVols, final DoubleMatrix1D initialGuess);  }
@Test(enabled = false) public void test() { final DoubleMatrix1D initalGuess = new DoubleMatrix1D(new double[] {0.2, 0.8, 0.3, 2.0, 0.9, 0.9 }); final TwoStateMarkovChainFitter fitter = new TwoStateMarkovChainFitter(THETA); final LeastSquareResultsWithTransform res = fitter.fit(FORWARD_CURVE, MARKET_VOLS, initalGuess); final double[] modelParms = res.getModelParameters().getData(); assertEquals(0.0, res.getChiSq(), 1e-3); assertEquals(VOL1, modelParms[0], 1e-3); assertEquals(DELTA_VOL, modelParms[1], 2e-3); assertEquals(LAMBDA12, modelParms[2], 2e-3); assertEquals(LAMBDA21, modelParms[3], 2e-3); assertEquals(P0, modelParms[4], 1e-3); assertEquals(BETA, modelParms[5], 1e-3); }