throw new OpenGammaRuntimeException("Could not get FX forward market data");
}
final YieldAndDiscountCurve foreignCurve = (YieldAndDiscountCurve) foreignCurveObject;
@SuppressWarnings("unchecked")
final Map<ExternalId, Double> fxForwardData = (Map<ExternalId, Double>) dataObject;
final DoubleArrayList marketValues = new DoubleArrayList();
final DoubleArrayList nodeTimes = new DoubleArrayList();
final DoubleArrayList initialRatesGuess = new DoubleArrayList();
final String fullDomesticCurveName = domesticCurveName + "_" + domesticCurrency.getCode();
final String fullForeignCurveName = foreignCurveName + "_" + foreignCurrency.getCode();
final List<InstrumentDerivative> derivatives = new ArrayList<>();
int nInstruments = 0;
final HolidaySource holidaySource = OpenGammaExecutionContext.getHolidaySource(executionContext);
final Calendar calendar = CalendarUtils.getCalendar(holidaySource, domesticCurrency, foreignCurrency);
final ConventionSource conventionSource = OpenGammaExecutionContext.getConventionSource(executionContext);
final FXSpotConvention fxSpotConvention = (FXSpotConvention) conventionSource.getConvention(ExternalId.of("CONVENTION", "FX Spot"));
final int spotLag = fxSpotConvention.getSettlementDays();
final ExternalId conventionSettlementRegion = fxSpotConvention.getSettlementRegion();
ZonedDateTime spotDate;
if (spotLag == 0 && conventionSettlementRegion == null) {
spotDate = now; //This preserves the old behaviour that ignored holidays and settlement days.
} else {
spotDate = ScheduleCalculator.getAdjustedDate(now, spotLag, calendar);
}
for (final Tenor tenor : definition.getTenors()) {
final ExternalId identifier = provider.getInstrument(now.toLocalDate(), tenor);
if (fxForwardData.containsKey(identifier)) {
final ZonedDateTime paymentDate;
if (spotLag == 0 && conventionSettlementRegion == null) {
paymentDate = now.plus(tenor.getPeriod()); //This preserves the old behaviour that ignored holidays and settlement days.
} else {
paymentDate = ScheduleCalculator.getAdjustedDate(spotDate, tenor.getPeriod(), MOD_FOL, calendar, true);
}
final double paymentTime = TimeCalculator.getTimeBetween(now, paymentDate);
final double forwardFX = invertFXQuotes ? 1 / fxForwardData.get(identifier) : fxForwardData.get(identifier);
derivatives.add(getFXForward(domesticCurrency, foreignCurrency, paymentTime, spotFX, forwardFX, fullDomesticCurveName, fullForeignCurveName));
marketValues.add(forwardFX);
nodeTimes.add(paymentTime);
if (nInstruments > 1 && CompareUtils.closeEquals(nodeTimes.get(nInstruments - 1), paymentTime, 1e-12)) {
throw new OpenGammaRuntimeException("FX forward with tenor " + tenor + " has already been added - will lead to equal nodes in the curve. Remove one of these tenors.");
}
nInstruments++;
initialRatesGuess.add(0.02);
}
}
final YieldCurveBundle knownCurve = new YieldCurveBundle(new String[] {fullForeignCurveName }, new YieldAndDiscountCurve[] {foreignCurve });
final LinkedHashMap<String, double[]> curveKnots = new LinkedHashMap<>();
curveKnots.put(fullDomesticCurveName, nodeTimes.toDoubleArray());
final LinkedHashMap<String, double[]> curveNodes = new LinkedHashMap<>();
final LinkedHashMap<String, Interpolator1D> interpolators = new LinkedHashMap<>();
final CombinedInterpolatorExtrapolator interpolator = CombinedInterpolatorExtrapolatorFactory.getInterpolator(interpolatorName, leftExtrapolatorName,
rightExtrapolatorName);
curveNodes.put(fullDomesticCurveName, nodeTimes.toDoubleArray());
interpolators.put(fullDomesticCurveName, interpolator);
final FXMatrix fxMatrix = new FXMatrix();
fxMatrix.addCurrency(foreignCurrency, domesticCurrency, spotFX);
final MultipleYieldCurveFinderDataBundle data = new MultipleYieldCurveFinderDataBundle(derivatives, marketValues.toDoubleArray(), knownCurve, curveNodes,
interpolators, useFiniteDifference, fxMatrix);
final NewtonVectorRootFinder rootFinder = new BroydenVectorRootFinder(absoluteTolerance, relativeTolerance, iterations, decomposition);
final Function1D<DoubleMatrix1D, DoubleMatrix1D> curveCalculator = new MultipleYieldCurveFinderFunction(data, PAR_RATE_CALCULATOR);
final Function1D<DoubleMatrix1D, DoubleMatrix2D> jacobianCalculator = new MultipleYieldCurveFinderJacobian(data, PAR_RATE_SENSITIVITY_CALCULATOR);
final double[] fittedYields = rootFinder.getRoot(curveCalculator, jacobianCalculator, new DoubleMatrix1D(initialRatesGuess.toDoubleArray())).getData();
final DoubleMatrix2D jacobianMatrix = jacobianCalculator.evaluate(new DoubleMatrix1D(fittedYields));
final YieldCurve curve = YieldCurve.from(InterpolatedDoublesCurve.from(nodeTimes.toDoubleArray(), fittedYields, interpolator));
final ComputationTargetSpecification targetSpec = target.toSpecification();
final ValueProperties curveProperties = getCurveProperties(curveCalculationConfigName, domesticCurveName, absoluteToleranceName, relativeToleranceName,
iterationsName, decompositionName, useFiniteDifferenceName, interpolatorName, leftExtrapolatorName, rightExtrapolatorName);