@Override
 public synchronized YieldCurveDefinitionDocument get(
     ObjectIdentifiable objectIdable, VersionCorrection versionCorrection) {
   ArgumentChecker.notNull(objectIdable, "objectIdable");
   ObjectId objectId = objectIdable.getObjectId();
   if (!getUniqueIdScheme().equals(objectId.getScheme())) {
     throw new DataNotFoundException(
         "Scheme '" + objectId.getScheme() + "' not valid for '" + getUniqueIdScheme() + "'");
   }
   final int i = objectId.getValue().indexOf('_');
   if (i <= 0) {
     throw new DataNotFoundException(
         "Identifier '" + objectId.getValue() + "' not valid for '" + getUniqueIdScheme() + "'");
   }
   final String name = objectId.getValue().substring(0, i);
   final String iso = objectId.getValue().substring(i + 1);
   final Currency currency;
   try {
     currency = Currency.of(iso);
   } catch (IllegalArgumentException e) {
     throw new DataNotFoundException(
         "Identifier '" + objectId.getValue() + "' not valid for '" + getUniqueIdScheme() + "'",
         e);
   }
   final TreeMap<Instant, YieldCurveDefinition> definitions =
       _definitions.get(Pair.of(currency, name));
   if (definitions == null) {
     throw new DataNotFoundException("Curve definition not found");
   }
   final YieldCurveDefinition definition = definitions.lastEntry().getValue();
   if (definition == null) {
     throw new DataNotFoundException("Curve definition not found");
   }
   return new YieldCurveDefinitionDocument(objectId.atLatestVersion(), definition);
 }
 @Override
 public IndexON buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
   final String name = message.getString(NAME_FIELD);
   final Currency currency = Currency.of(message.getString(CURRENCY_FIELD));
   final DayCount dayCount =
       DayCountFactory.INSTANCE.getDayCount(message.getString(DAY_COUNT_FIELD));
   final int publicationLag = message.getInt(PUBLICATION_LAG_FIELD);
   return new IndexON(name, currency, dayCount, publicationLag);
 }
 @Override
 public synchronized void remove(ObjectIdentifiable objectIdentifiable) {
   ArgumentChecker.notNull(objectIdentifiable, "objectIdentifiable");
   if (!getUniqueIdScheme().equals(objectIdentifiable.getObjectId().getScheme())) {
     throw new DataNotFoundException(
         "Scheme '"
             + objectIdentifiable.getObjectId().getScheme()
             + "' not valid for '"
             + getUniqueIdScheme()
             + "'");
   }
   final int i = objectIdentifiable.getObjectId().getValue().indexOf('_');
   if (i <= 0) {
     throw new DataNotFoundException(
         "Identifier '"
             + objectIdentifiable.getObjectId().getValue()
             + "' not valid for '"
             + getUniqueIdScheme()
             + "'");
   }
   final String name = objectIdentifiable.getObjectId().getValue().substring(0, i);
   final String iso = objectIdentifiable.getObjectId().getValue().substring(i + 1);
   final Currency currency;
   try {
     currency = Currency.of(iso);
   } catch (IllegalArgumentException e) {
     throw new DataNotFoundException(
         "Identifier '"
             + objectIdentifiable.getObjectId().getValue()
             + "' not valid for '"
             + getUniqueIdScheme()
             + "'",
         e);
   }
   final Pair<Currency, String> key = Pair.of(currency, name);
   if (_sourceVersionCorrection.getVersionAsOf() != null) {
     final TreeMap<Instant, YieldCurveDefinition> value = _definitions.get(key);
     if (value == null) {
       throw new DataNotFoundException("Curve definition not found");
     }
     // Don't need to keep the old values before the one needed by "versionAsOfInstant"
     final Instant oldestNeeded = value.floorKey(_sourceVersionCorrection.getVersionAsOf());
     if (oldestNeeded != null) {
       value.headMap(oldestNeeded).clear();
     }
     // Store a null to indicate the delete
     value.put(Instant.now(), null);
   } else {
     if (_definitions.remove(key) == null) {
       throw new DataNotFoundException("Curve definition not found");
     }
   }
   changeManager()
       .entityChanged(
           ChangeType.REMOVED, objectIdentifiable.getObjectId(), null, null, Instant.now());
 }
    @SuppressWarnings("synthetic-access")
    @Override
    public CurrencyLabelledMatrix1D buildObject(
        final FudgeDeserializer deserializer, final FudgeMsg message) {
      final FudgeMsg msg = message.getMessage(MATRIX_FIELD_NAME);

      final Queue<String> labelTypes = new LinkedList<String>();
      final Queue<FudgeField> labelValues = new LinkedList<FudgeField>();

      final List<Currency> keys = new LinkedList<Currency>();
      final List<Object> labels = new LinkedList<Object>();
      final List<Double> values = new LinkedList<Double>();

      for (final FudgeField field : msg) {
        switch (field.getOrdinal()) {
          case LABEL_TYPE_ORDINAL:
            labelTypes.add((String) field.getValue());
            break;
          case KEY_ORDINAL:
            keys.add(Currency.of((String) field.getValue()));
            break;
          case LABEL_ORDINAL:
            labelValues.add(field);
            break;
          case VALUE_ORDINAL:
            values.add((Double) field.getValue());
            break;
        }

        if (!labelTypes.isEmpty() && !labelValues.isEmpty()) {
          // Have a type and a value, which can be consumed
          final String labelType = labelTypes.remove();
          Class<?> labelClass;
          try {
            labelClass = LabelledMatrix1DBuilder.getLabelClass(labelType, _loadedClasses);
          } catch (final ClassNotFoundException ex) {
            throw new OpenGammaRuntimeException(
                "Could not deserialize label of type " + labelType, ex);
          }
          final FudgeField labelValue = labelValues.remove();
          final Object label = deserializer.fieldValueToObject(labelClass, labelValue);
          //          labels.add(Currency.of((String) label));
          labels.add(label);
        }
      }

      final int matrixSize = keys.size();
      final Currency[] keysArray = new Currency[matrixSize];
      keys.toArray(keysArray);
      final Object[] labelsArray = new Object[matrixSize];
      labels.toArray(labelsArray);
      final double[] valuesArray = Doubles.toArray(values);
      return new CurrencyLabelledMatrix1D(keysArray, labelsArray, valuesArray);
    }
 @Override
 public IborIndex buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
   final Currency currency = Currency.of(message.getString(CURRENCY_FIELD));
   final int spotLag = message.getInt(SPOT_LAG_FIELD);
   final DayCount dayCount =
       DayCountFactory.INSTANCE.getDayCount(message.getString(DAY_COUNT_FIELD));
   final BusinessDayConvention businessDayConvention =
       BusinessDayConventionFactory.INSTANCE.getBusinessDayConvention(
           message.getString(BUSINESS_DAY_CONVENTION_FIELD));
   final boolean isEOM = message.getBoolean(EOM_FIELD);
   final Period tenor = Period.parse(message.getString(TENOR_FIELD));
   final String name = message.getString(NAME_FIELD);
   return new IborIndex(currency, tenor, spotLag, dayCount, businessDayConvention, isEOM, name);
 }
Ejemplo n.º 6
0
 // -------------------------------------------------------------------------
 @Override
 protected void doRun() {
   ToolContext toolContext = getToolContext();
   CommandLine commandLine = getCommandLine();
   boolean verbose = commandLine.hasOption("verbose");
   if ((commandLine.hasOption("today") && commandLine.hasOption("yesterday"))
       || (commandLine.hasOption("date") && commandLine.hasOption("today"))
       || (commandLine.hasOption("date") && commandLine.hasOption("yesterday"))) {
     System.err.println("Can only return today OR yesterday OR date!");
     System.exit(2);
   }
   String ccyStr = commandLine.getOptionValue("ccy");
   try {
     Currency ccy = Currency.of(ccyStr);
     LocalDate date = null;
     if (commandLine.hasOption("yesterday")) {
       date = LocalDate.now().minusDays(1);
     } else if (commandLine.hasOption("today")) {
       date = LocalDate.now();
     } else if (commandLine.hasOption("date")) {
       try {
         date =
             (LocalDate)
                 DateTimeFormatter.BASIC_ISO_DATE.parse(commandLine.getOptionValue("date"));
       } catch (Exception e) {
         System.err.println("Could not parse date, should be YYYYMMDD format");
         System.exit(2);
       }
     } else {
       System.err.println("Must specify either today or yesterday option");
       System.exit(2);
     }
     boolean isHoliday = toolContext.getHolidaySource().isHoliday(date, ccy);
     if (isHoliday) {
       if (verbose) {
         System.out.println("Day was a holiday");
       }
       System.exit(0);
     } else {
       if (verbose) {
         System.out.println("Day was not a holiday");
       }
       System.exit(1);
     }
   } catch (IllegalArgumentException iae) {
     System.err.println("Invalid currency code");
     System.exit(2);
   }
 }
 @Override
 public MulticurveProviderDiscount buildObject(
     final FudgeDeserializer deserializer, final FudgeMsg message) {
   final Map<Currency, YieldAndDiscountCurve> discountingCurves = new LinkedHashMap<>();
   final List<FudgeField> currencyFields = message.getAllByName(CURRENCY_FIELD);
   final List<FudgeField> discountingCurveFields = message.getAllByName(DISCOUNTING_CURVE_FIELD);
   for (int i = 0; i < currencyFields.size(); i++) {
     final Currency currency = Currency.of((String) currencyFields.get(i).getValue());
     final YieldAndDiscountCurve curve =
         deserializer.fudgeMsgToObject(
             YieldAndDiscountCurve.class, (FudgeMsg) discountingCurveFields.get(i).getValue());
     discountingCurves.put(currency, curve);
   }
   final Map<IborIndex, YieldAndDiscountCurve> forwardIborCurves = new LinkedHashMap<>();
   final List<FudgeField> indexIborFields = message.getAllByName(INDEX_IBOR_FIELD);
   final List<FudgeField> forwardIborCurveFields = message.getAllByName(INDEX_IBOR_CURVE);
   for (int i = 0; i < currencyFields.size(); i++) {
     final IborIndex index =
         deserializer.fudgeMsgToObject(
             IborIndex.class, (FudgeMsg) indexIborFields.get(i).getValue());
     final YieldAndDiscountCurve curve =
         deserializer.fudgeMsgToObject(
             YieldAndDiscountCurve.class, (FudgeMsg) forwardIborCurveFields.get(i).getValue());
     forwardIborCurves.put(index, curve);
   }
   final Map<IndexON, YieldAndDiscountCurve> forwardONCurves = new LinkedHashMap<>();
   final List<FudgeField> indexONFields = message.getAllByName(INDEX_ON_FIELD);
   final List<FudgeField> forwardONCurveFields = message.getAllByName(OVERNIGHT_CURVE_FIELD);
   for (int i = 0; i < currencyFields.size(); i++) {
     final IndexON index =
         deserializer.fudgeMsgToObject(
             IndexON.class, (FudgeMsg) indexONFields.get(i).getValue());
     final YieldAndDiscountCurve curve =
         deserializer.fudgeMsgToObject(
             YieldAndDiscountCurve.class, (FudgeMsg) forwardONCurveFields.get(i).getValue());
     forwardONCurves.put(index, curve);
   }
   final FXMatrix fxMatrix =
       deserializer.fieldValueToObject(FXMatrix.class, message.getByName(FX_MATRIX_FIELD));
   return new MulticurveProviderDiscount(
       discountingCurves, forwardIborCurves, forwardONCurves, fxMatrix);
 }
 @Override
 public FXMatrix buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
   final List<FudgeField> currencies = message.getAllByName(CURRENCY_FIELD);
   final List<FudgeField> orders = message.getAllByName(ORDER_FIELD);
   final Map<Currency, Integer> map = new HashMap<>();
   for (int i = 0; i < currencies.size(); i++) {
     final Currency currency = Currency.of((String) currencies.get(i).getValue());
     final Integer order = ((Number) orders.get(i).getValue()).intValue();
     map.put(currency, order);
   }
   final List<FudgeField> entries = message.getAllByName(ENTRIES_FIELD);
   final List<FudgeField> arrays = message.getAllByName(FX_RATES_FIELD);
   final double[][] fxRates = new double[entries.size()][];
   for (int i = 0; i < entries.size(); i++) {
     final FudgeMsg msg = (FudgeMsg) arrays.get(i).getValue();
     final double[] row =
         deserializer.fieldValueToObject(double[].class, msg.getByName(ROW_FIELD));
     fxRates[i] = row;
   }
   return new FXMatrix(map, fxRates);
 }
 @Override
 public synchronized YieldCurveDefinitionDocument get(UniqueId uid) {
   ArgumentChecker.notNull(uid, "objectIdentifiable");
   if (!uid.isLatest()) {
     throw new IllegalArgumentException(
         "Only latest version supported by '" + getUniqueIdScheme() + "'");
   }
   if (!getUniqueIdScheme().equals(uid.getScheme())) {
     throw new DataNotFoundException(
         "Scheme '" + uid.getScheme() + "' not valid for '" + getUniqueIdScheme() + "'");
   }
   final int i = uid.getValue().indexOf('_');
   if (i <= 0) {
     throw new DataNotFoundException(
         "Identifier '" + uid.getValue() + "' not valid for '" + getUniqueIdScheme() + "'");
   }
   final String name = uid.getValue().substring(0, i);
   final String iso = uid.getValue().substring(i + 1);
   final Currency currency;
   try {
     currency = Currency.of(iso);
   } catch (IllegalArgumentException e) {
     throw new DataNotFoundException(
         "Identifier '" + uid.getValue() + "' not valid for '" + getUniqueIdScheme() + "'", e);
   }
   final TreeMap<Instant, YieldCurveDefinition> definitions =
       _definitions.get(Pair.of(currency, name));
   if (definitions == null) {
     throw new DataNotFoundException("Curve definition not found");
   }
   final YieldCurveDefinition definition = definitions.lastEntry().getValue();
   if (definition == null) {
     throw new DataNotFoundException("Curve definition not found");
   }
   return new YieldCurveDefinitionDocument(uid, definition);
 }
public class ForexNonDeliverableOptionDefinitionTest {

  private static final Currency KRW = Currency.of("KRW");
  private static final Currency USD = Currency.EUR;
  private static final ZonedDateTime FIXING_DATE = DateUtils.getUTCDate(2012, 5, 2);
  private static final ZonedDateTime PAYMENT_DATE = DateUtils.getUTCDate(2012, 5, 4);
  private static final double NOMINAL_USD = 1000000; // 1m
  private static final double STRIKE_USD_KRW = 1123.45;
  private static final ForexNonDeliverableForwardDefinition NDF_DEFINITION =
      new ForexNonDeliverableForwardDefinition(
          KRW, USD, NOMINAL_USD, STRIKE_USD_KRW, FIXING_DATE, PAYMENT_DATE);

  private static final boolean IS_CALL = true;
  private static final boolean IS_LONG = true;
  private static final ForexNonDeliverableOptionDefinition NDO_DEFINITION =
      new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, IS_CALL, IS_LONG);

  private static final ZonedDateTime REFERENCE_DATE = DateUtils.getUTCDate(2011, 11, 10);
  private static final String KRW_DSC = "Discounting KRW";
  private static final String USD_DSC = "Discounting USD";
  private static final String[] CURVE_NAMES = new String[] {KRW_DSC, USD_DSC};

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullFX() {
    new ForexNonDeliverableOptionDefinition(null, IS_CALL, IS_LONG);
  }

  @Test
  public void getter() {
    assertEquals(
        "Forex non-deliverable option - getter", NDF_DEFINITION, NDO_DEFINITION.getUnderlyingNDF());
    assertEquals("Forex non-deliverable option - getter", IS_CALL, NDO_DEFINITION.isCall());
    assertEquals("Forex non-deliverable option - getter", IS_LONG, NDO_DEFINITION.isLong());
  }

  @Test
  /** Tests the class toDerivative method. */
  public void toDerivative() {
    ForexNonDeliverableOption ndoConverted =
        NDO_DEFINITION.toDerivative(REFERENCE_DATE, CURVE_NAMES);
    ForexNonDeliverableOption ndoExpected =
        new ForexNonDeliverableOption(
            NDF_DEFINITION.toDerivative(REFERENCE_DATE, CURVE_NAMES), IS_CALL, IS_LONG);
    assertEquals("Forex NDO - toDerivatives", ndoExpected, ndoConverted);
  }

  @Test
  /** Tests the class equal and hashCode */
  public void equalHash() {
    assertEquals(
        "ForexNonDeliverableOptionDefinition: equal/hash code", NDO_DEFINITION, NDO_DEFINITION);
    assertFalse(
        "ForexNonDeliverableOptionDefinition: equal/hash code", NDO_DEFINITION.equals(CURVE_NAMES));
    assertFalse(
        "ForexNonDeliverableOptionDefinition: equal/hash code", NDO_DEFINITION.equals(null));
    final ForexNonDeliverableOptionDefinition newNdo =
        new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, IS_CALL, IS_LONG);
    assertTrue(
        "ForexNonDeliverableOptionDefinition: equal/hash code", NDO_DEFINITION.equals(newNdo));
    assertTrue(
        "ForexNonDeliverableOptionDefinition: equal/hash code",
        NDO_DEFINITION.hashCode() == newNdo.hashCode());
    final ForexNonDeliverableOptionDefinition newNdo2 =
        new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, !IS_CALL, !IS_LONG);
    final ForexNonDeliverableOptionDefinition newNdo3 =
        new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, !IS_CALL, !IS_LONG);
    assertEquals(
        "ForexNonDeliverableOptionDefinition: equal/hash code",
        newNdo2.hashCode(),
        newNdo3.hashCode());
    ForexNonDeliverableOptionDefinition modifiedNdo;
    modifiedNdo =
        new ForexNonDeliverableOptionDefinition(
            new ForexNonDeliverableForwardDefinition(
                KRW, USD, NOMINAL_USD, STRIKE_USD_KRW + 1.0, FIXING_DATE, PAYMENT_DATE),
            IS_CALL,
            IS_LONG);
    assertFalse("Forex NDF: equal - hash code", NDO_DEFINITION.equals(modifiedNdo));
    modifiedNdo = new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, !IS_CALL, IS_LONG);
    assertFalse("Forex NDF: equal - hash code", NDO_DEFINITION.equals(modifiedNdo));
    modifiedNdo = new ForexNonDeliverableOptionDefinition(NDF_DEFINITION, IS_CALL, !IS_LONG);
    assertFalse("Forex NDF: equal - hash code", NDO_DEFINITION.equals(modifiedNdo));
    assertFalse(NDF_DEFINITION.equals(USD));
    assertFalse(NDF_DEFINITION.equals(null));
  }
}
Ejemplo n.º 11
0
  /**
   * Parses the specified file to populate the master.
   *
   * @param in the input reader to read, not closed, not null
   */
  public void parse(Reader in) {
    String name = null;
    try {
      Map<String, ManageableRegion> regions = new HashMap<String, ManageableRegion>();
      Map<UniqueId, Set<String>> subRegions = new HashMap<UniqueId, Set<String>>();

      // open CSV file
      @SuppressWarnings("resource")
      CSVReader reader = new CSVReader(in);
      List<String> columns = Arrays.asList(reader.readNext());

      // identify columns
      final int nameColumnIdx = columns.indexOf(NAME_COLUMN);
      final int formalNameColumnIdx = columns.indexOf(FORMAL_NAME_COLUMN);
      final int classificationColumnIdx = columns.indexOf(CLASSIFICATION_COLUMN);
      final int sovereignityColumnIdx = columns.indexOf(SOVEREIGNITY_COLUMN);
      final int countryColumnIdx = columns.indexOf(ISO_COUNTRY_2_COLUMN);
      final int currencyColumnIdx = columns.indexOf(ISO_CURRENCY_3_COLUMN);
      final int subRegionsColumnIdx = columns.indexOf(SUB_REGIONS_COLUMN);

      // parse
      String[] row = null;
      while ((row = reader.readNext()) != null) {
        name = row[nameColumnIdx].trim(); // the primary key
        String fullName = StringUtils.trimToNull(row[formalNameColumnIdx]);
        if (fullName == null) {
          fullName = name;
        }
        RegionClassification classification =
            RegionClassification.valueOf(row[classificationColumnIdx].trim());
        String sovereignity = StringUtils.trimToNull(row[sovereignityColumnIdx]);
        String countryISO = StringUtils.trimToNull(row[countryColumnIdx]);
        String currencyISO = StringUtils.trimToNull(row[currencyColumnIdx]);
        Set<String> rowSubRegions =
            new HashSet<String>(Arrays.asList(row[subRegionsColumnIdx].split(";")));
        rowSubRegions = trim(rowSubRegions);

        ManageableRegion region = new ManageableRegion();
        region.setClassification(classification);
        region.setName(name);
        region.setFullName(fullName);
        if (countryISO != null) {
          region.setCountry(Country.of(countryISO));
          region.addExternalId(ExternalSchemes.financialRegionId(countryISO)); // TODO: looks odd
        }
        if (currencyISO != null) {
          region.setCurrency(Currency.of(currencyISO));
        }
        if (sovereignity != null) {
          ManageableRegion parent = regions.get(sovereignity);
          if (parent == null) {
            throw new OpenGammaRuntimeException(
                "Cannot find parent '" + sovereignity + "'  for '" + name + "'");
          }
          region.getParentRegionIds().add(parent.getUniqueId());
        }
        for (Entry<UniqueId, Set<String>> entry : subRegions.entrySet()) {
          if (entry.getValue().remove(name)) {
            region.getParentRegionIds().add(entry.getKey());
          }
        }

        // store
        RegionDocument doc = getRegionMaster().add(new RegionDocument(region));
        if (rowSubRegions.size() > 0) {
          subRegions.put(doc.getUniqueId(), rowSubRegions);
        }
        regions.put(name, region);
      }
      for (Set<String> set : subRegions.values()) {
        if (set.size() > 0) {
          throw new OpenGammaRuntimeException("Cannot find children: " + set);
        }
      }

    } catch (Exception ex) {
      String detail = (name != null ? " while processing " + name : "");
      throw new OpenGammaRuntimeException(
          "Cannot open region data file (or file I/O problem)" + detail, ex);
    }
  }
 public YieldCurveMarketDataFunction(final String currency, final String curveDefinitionName) {
   this(Currency.of(currency), curveDefinitionName);
 }
Ejemplo n.º 13
0
 /**
  * Gets the currency.
  *
  * @return the value of the property
  */
 public Currency getCurrency() {
   String code = _externalIdBundle.getValue(ExternalSchemes.ISO_CURRENCY_ALPHA3);
   return (code != null ? Currency.of(code) : null);
 }
 @Override
 public Set<ValueRequirement> getRequirements(
     final FunctionCompilationContext context,
     final ComputationTarget target,
     final ValueRequirement desiredValue) {
   final ValueProperties constraints = desiredValue.getConstraints();
   final Set<String> payCurveNames = constraints.getValues(ValuePropertyNames.PAY_CURVE);
   if (payCurveNames == null || payCurveNames.size() != 1) {
     return null;
   }
   final Set<String> payCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG);
   if (payCurveCalculationConfigs == null || payCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveNames = constraints.getValues(ValuePropertyNames.RECEIVE_CURVE);
   if (receiveCurveNames == null || receiveCurveNames.size() != 1) {
     return null;
   }
   final Set<String> receiveCurveCalculationConfigs =
       constraints.getValues(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG);
   if (receiveCurveCalculationConfigs == null || receiveCurveCalculationConfigs.size() != 1) {
     return null;
   }
   final Set<String> calculationMethods =
       constraints.getValues(ValuePropertyNames.CALCULATION_METHOD);
   if (calculationMethods == null || calculationMethods.size() != 1) {
     final ValueProperties newConstraints =
         constraints
             .copy()
             .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
             .with(
                 ValuePropertyNames.CALCULATION_METHOD,
                 CalculationPropertyNamesAndValues.DISCOUNTING)
             .get();
     return Collections.singleton(
         new ValueRequirement(
             ValueRequirementNames.PNL_SERIES, target.toSpecification(), newConstraints));
   }
   final Set<ValueRequirement> requirements = new HashSet<>();
   final String calculationMethod = Iterables.getOnlyElement(calculationMethods);
   final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
   if (CalculationPropertyNamesAndValues.DISCOUNTING.equals(calculationMethod)) {
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.DISCOUNTING)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .get()));
   } else if (CalculationPropertyNamesAndValues.FORWARD_POINTS.equals(calculationMethod)) {
     final Set<String> forwardCurveNames =
         constraints.getValues(ValuePropertyNames.FORWARD_CURVE_NAME);
     if (forwardCurveNames == null || forwardCurveNames.size() != 1) {
       return null;
     }
     final String forwardCurveName = Iterables.getOnlyElement(forwardCurveNames);
     requirements.add(
         new ValueRequirement(
             ValueRequirementNames.FX_CURRENCY_EXPOSURE,
             ComputationTargetSpecification.of(target.getPosition().getSecurity()),
             ValueProperties.builder()
                 .with(
                     ValuePropertyNames.CALCULATION_METHOD,
                     CalculationPropertyNamesAndValues.FORWARD_POINTS)
                 .with(ValuePropertyNames.PAY_CURVE, payCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG,
                     payCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.RECEIVE_CURVE, receiveCurveNames.iterator().next())
                 .with(
                     ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG,
                     receiveCurveCalculationConfigs.iterator().next())
                 .with(ValuePropertyNames.FORWARD_CURVE_NAME, forwardCurveName)
                 .get()));
   } else {
     return null;
   }
   final Set<String> resultCurrencies = constraints.getValues(CURRENCY);
   final Currency payCurrency = security.accept(ForexVisitors.getPayCurrencyVisitor());
   final Currency receiveCurrency = security.accept(ForexVisitors.getReceiveCurrencyVisitor());
   final String resultCurrency;
   final CurrencyPair baseQuotePair =
       _currencyPairs.getCurrencyPair(payCurrency, receiveCurrency);
   final Currency baseCurrency = baseQuotePair.getBase();
   final Currency nonBaseCurrency = baseQuotePair.getCounter();
   if (resultCurrencies != null && resultCurrencies.size() == 1) {
     final Currency ccy = Currency.of(Iterables.getOnlyElement(resultCurrencies));
     if (!(ccy.equals(payCurrency) || ccy.equals(receiveCurrency))) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, ccy)));
       resultCurrency = ccy.getCode();
     } else if (ccy.equals(nonBaseCurrency)) {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(nonBaseCurrency, baseCurrency)));
       resultCurrency = nonBaseCurrency.getCode();
     } else {
       requirements.add(
           ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(
               UnorderedCurrencyPair.of(baseCurrency, nonBaseCurrency)));
       resultCurrency = baseCurrency.getCode();
     }
   } else {
     resultCurrency = baseCurrency.getCode();
   }
   final ValueProperties fxSpotConstraints =
       desiredValue
           .getConstraints()
           .copy()
           .withoutAny(ValuePropertyNames.PAY_CURVE)
           .withoutAny(ValuePropertyNames.PAY_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE)
           .withoutAny(ValuePropertyNames.RECEIVE_CURVE_CALCULATION_CONFIG)
           .withoutAny(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS)
           .withoutAny(ValuePropertyNames.CURVE_CURRENCY)
           .withoutAny(ValuePropertyNames.CALCULATION_METHOD)
           .withoutAny(ValuePropertyNames.FORWARD_CURVE_NAME)
           .with(CURRENCY, resultCurrency)
           .withOptional(CURRENCY)
           .get();
   final ComputationTargetSpecification fxSpotReturnSeriesSpec =
       ComputationTargetType.UNORDERED_CURRENCY_PAIR.specification(
           UnorderedCurrencyPair.of(payCurrency, receiveCurrency));
   requirements.add(
       new ValueRequirement(
           ValueRequirementNames.RETURN_SERIES, fxSpotReturnSeriesSpec, fxSpotConstraints));
   return requirements;
 }
Ejemplo n.º 15
0
/** Tests related to the FXMatrix. */
@Test(groups = TestGroup.UNIT)
public class FXMatrixTest {

  private static final Currency USD = Currency.USD;
  private static final Currency EUR = Currency.EUR;
  private static final Currency GBP = Currency.GBP;
  private static final Currency KRW = Currency.of("KRW");

  private static final double EUR_USD = 1.40;
  private static final double GBP_EUR = 1.20;
  private static final double USD_KRW = 1123.45;

  private static final double TOLERANCE_RATE = 1.0E-10;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullCurrencyConstructor1() {
    new FXMatrix((Currency) null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullCurrency1() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(null, USD, EUR_USD);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void nullCurrency2() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, null, EUR_USD);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void sameCurrency() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, EUR, EUR_USD);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void currency1NotPresent() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.getFxRate(GBP, USD);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void currency2NotPresent() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.getFxRate(USD, GBP);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void currencyAlreadyPresent() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix.addCurrency(GBP, USD, 1.234);
  }

  @Test
  public void onePair() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    assertEquals("FXMatrix - first pair", EUR_USD, fxMatrix.getFxRate(EUR, USD), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - first pair", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - first pair",
        1.0,
        fxMatrix.getFxRate(USD, USD),
        TOLERANCE_RATE); // Is this useful? At least it is correct!
    assertEquals("FXMatrix - first pair", 1.0, fxMatrix.getFxRate(EUR, EUR), TOLERANCE_RATE);
  }

  @Test
  public void onePairSecondConstructor() {
    final FXMatrix fxMatrix = new FXMatrix(EUR, USD, EUR_USD);
    assertEquals("FXMatrix - first pair", EUR_USD, fxMatrix.getFxRate(EUR, USD), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - first pair", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - first pair",
        1.0,
        fxMatrix.getFxRate(USD, USD),
        TOLERANCE_RATE); // Is this useful? At least it is correct!
    assertEquals("FXMatrix - first pair", 1.0, fxMatrix.getFxRate(EUR, EUR), TOLERANCE_RATE);
  }

  @Test
  public void onePairThirdConstructor() {
    final FXMatrix fxMatrix = new FXMatrix(USD);
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    assertEquals("FXMatrix - first pair", EUR_USD, fxMatrix.getFxRate(EUR, USD), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - first pair", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), TOLERANCE_RATE);
    assertEquals("FXMatrix - first pair", 1.0, fxMatrix.getFxRate(USD, USD), TOLERANCE_RATE);
    assertEquals("FXMatrix - first pair", 1.0, fxMatrix.getFxRate(EUR, EUR), TOLERANCE_RATE);
  }

  @Test
  public void twoPairs() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    assertEquals("FXMatrix - two pairs", EUR_USD, fxMatrix.getFxRate(EUR, USD), 1.0E-10);
    assertEquals("FXMatrix - two pairs", GBP_EUR, fxMatrix.getFxRate(GBP, EUR), 1.0E-10);
    assertEquals("FXMatrix - two pairs", GBP_EUR * EUR_USD, fxMatrix.getFxRate(GBP, USD), 1.0E-10);
    assertEquals("FXMatrix - two pairs", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), 1.0E-10);
    assertEquals("FXMatrix - two pairs", 1.0 / GBP_EUR, fxMatrix.getFxRate(EUR, GBP), 1.0E-10);
    assertEquals(
        "FXMatrix - two pairs", 1.0 / (GBP_EUR * EUR_USD), fxMatrix.getFxRate(USD, GBP), 1.0E-10);
    assertEquals(
        "FXMatrix - two pairs",
        1.0,
        fxMatrix.getFxRate(GBP, GBP),
        1.0E-10); // Is this useful? At least it is correct!
  }

  @Test
  public void threePairs() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix.addCurrency(KRW, USD, 1.0 / USD_KRW);
    assertEquals("FXMatrix - three pairs", EUR_USD, fxMatrix.getFxRate(EUR, USD), 1.0E-10);
    assertEquals("FXMatrix - three pairs", GBP_EUR, fxMatrix.getFxRate(GBP, EUR), 1.0E-10);
    assertEquals(
        "FXMatrix - three pairs", GBP_EUR * EUR_USD, fxMatrix.getFxRate(GBP, USD), 1.0E-10);
    assertEquals("FXMatrix - three pairs", USD_KRW, fxMatrix.getFxRate(USD, KRW), 1.0E-10);
    assertEquals("FXMatrix - three pairs", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), 1.0E-10);
    assertEquals("FXMatrix - three pairs", 1.0 / GBP_EUR, fxMatrix.getFxRate(EUR, GBP), 1.0E-10);
    assertEquals(
        "FXMatrix - three pairs", 1.0 / (GBP_EUR * EUR_USD), fxMatrix.getFxRate(USD, GBP), 1.0E-10);
    assertEquals("FXMatrix - three pairs", 1.0 / USD_KRW, fxMatrix.getFxRate(KRW, USD), 1.0E-10);
    assertEquals(
        "FXMatrix - three pairs",
        GBP_EUR * EUR_USD * USD_KRW,
        fxMatrix.getFxRate(GBP, KRW),
        1.0E-10);
  }

  @Test
  public void constructorFromExisitingFxMatrix() {
    final FXMatrix fxMatrix1 = new FXMatrix(EUR, USD, EUR_USD);
    final FXMatrix fxMatrix2 = new FXMatrix(fxMatrix1);
    assertEquals("FXMatrix - constructor", fxMatrix1, fxMatrix2);
    fxMatrix2.addCurrency(GBP, EUR, GBP_EUR);
    assertFalse("FXMatrix - constructor", fxMatrix1.equals(fxMatrix2));
  }

  @Test
  /** Check the conversion of a multiple currency amount. */
  public void convert() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    final double amountGBP = 1.0;
    final double amountEUR = 2.0;
    final double amountUSD = 3.0;
    MultipleCurrencyAmount amount = MultipleCurrencyAmount.of(GBP, amountGBP);
    amount = amount.plus(EUR, amountEUR);
    amount = amount.plus(USD, amountUSD);
    final CurrencyAmount totalUSDCalculated = fxMatrix.convert(amount, USD);
    final double totalUSDExpected = amountUSD + amountEUR * EUR_USD + amountGBP * GBP_EUR * EUR_USD;
    assertEquals("FXMatrix - convert", totalUSDExpected, totalUSDCalculated.getAmount(), 1.0E-10);
    assertEquals("FXMatrix - convert", USD, totalUSDCalculated.getCurrency());
  }

  @Test
  /** Check the update of one exchange rate in matrix. */
  public void update() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix.addCurrency(KRW, USD, 1.0 / USD_KRW);
    assertEquals("FXMatrix - update", EUR_USD, fxMatrix.getFxRate(EUR, USD), TOLERANCE_RATE);
    assertEquals("FXMatrix - update", GBP_EUR, fxMatrix.getFxRate(GBP, EUR), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - update", GBP_EUR * EUR_USD, fxMatrix.getFxRate(GBP, USD), TOLERANCE_RATE);
    assertEquals("FXMatrix - update", USD_KRW, fxMatrix.getFxRate(USD, KRW), TOLERANCE_RATE);
    final double newGBPEUR = 1.10;
    fxMatrix.updateRates(GBP, EUR, newGBPEUR);
    assertEquals("FXMatrix - update", EUR_USD, fxMatrix.getFxRate(EUR, USD), TOLERANCE_RATE);
    assertEquals("FXMatrix - update", newGBPEUR, fxMatrix.getFxRate(GBP, EUR), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - update", newGBPEUR * EUR_USD, fxMatrix.getFxRate(GBP, USD), TOLERANCE_RATE);
    assertEquals("FXMatrix - update", USD_KRW, fxMatrix.getFxRate(USD, KRW), TOLERANCE_RATE);
    assertEquals("FXMatrix - update", 1.0 / EUR_USD, fxMatrix.getFxRate(USD, EUR), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - update", 1.0 / newGBPEUR, fxMatrix.getFxRate(EUR, GBP), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - update",
        1.0 / (newGBPEUR * EUR_USD),
        fxMatrix.getFxRate(USD, GBP),
        TOLERANCE_RATE);
    assertEquals("FXMatrix - update", 1.0 / USD_KRW, fxMatrix.getFxRate(KRW, USD), TOLERANCE_RATE);
    assertEquals(
        "FXMatrix - update",
        newGBPEUR * EUR_USD * USD_KRW,
        fxMatrix.getFxRate(GBP, KRW),
        TOLERANCE_RATE);
  }

  @Test
  public void testHashCodeEquals() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix.addCurrency(KRW, USD, 1.0 / USD_KRW);
    FXMatrix other = new FXMatrix();
    other.addCurrency(EUR, USD, EUR_USD);
    other.addCurrency(GBP, EUR, GBP_EUR);
    other.addCurrency(KRW, USD, 1.0 / USD_KRW);
    assertEquals(fxMatrix, other);
    assertEquals(fxMatrix.hashCode(), other.hashCode());
    other = new FXMatrix();
    other.addCurrency(EUR, USD, EUR_USD);
    other.addCurrency(GBP, EUR, GBP_EUR);
    assertFalse(fxMatrix.equals(other));
  }

  @Test
  /** Tests that a matrix merged with itself is equal with itself. */
  public void mergeWithItself() {
    final FXMatrix fxMatrix = new FXMatrix();
    fxMatrix.addCurrency(EUR, USD, EUR_USD);
    fxMatrix.addCurrency(GBP, EUR, GBP_EUR);
    final FXMatrix merged = FXMatrixUtils.merge(fxMatrix, fxMatrix);
    assertEquals("FXMatrixUtils - merge", fxMatrix, merged);
  }

  @Test
  /**
   * Tests that a matrix constructed by adding currencies one by one or by merging by blocks returns
   * the same result.
   */
  public void merge1() {
    final FXMatrix fxMatrixEURUSD = new FXMatrix();
    fxMatrixEURUSD.addCurrency(EUR, USD, EUR_USD);
    //    assertTrue("FXMatrixUtils - merge", FXMatrixUtils.compare(fxMatrixEURUSD,
    // FXMatrixUtils.merge(fxMatrixEURUSD, new FXMatrix()), TOLERANCE_RATE));
    //    assertTrue("FXMatrixUtils - merge", FXMatrixUtils.compare(fxMatrixEURUSD,
    // FXMatrixUtils.merge(new FXMatrix(), fxMatrixEURUSD), TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrixEURUSD,
            FXMatrixUtils.merge(fxMatrixEURUSD, new FXMatrix(USD)),
            TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrixEURUSD,
            FXMatrixUtils.merge(fxMatrixEURUSD, new FXMatrix(EUR)),
            TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrixEURUSD,
            FXMatrixUtils.merge(new FXMatrix(USD), fxMatrixEURUSD),
            TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrixEURUSD,
            FXMatrixUtils.merge(new FXMatrix(EUR), fxMatrixEURUSD),
            TOLERANCE_RATE));
    final FXMatrix fxMatrixGBPEUR = new FXMatrix();
    fxMatrixGBPEUR.addCurrency(GBP, EUR, GBP_EUR);
    final FXMatrix fxMatrixEURUSDGBP = new FXMatrix();
    fxMatrixEURUSDGBP.addCurrency(EUR, USD, EUR_USD);
    fxMatrixEURUSDGBP.addCurrency(GBP, EUR, GBP_EUR);
    final FXMatrix merged = FXMatrixUtils.merge(fxMatrixEURUSD, fxMatrixGBPEUR);
    assertTrue(
        "FXMatrixUtils - merge", FXMatrixUtils.compare(merged, fxMatrixEURUSDGBP, TOLERANCE_RATE));
  }

  @Test
  /**
   * Tests that a matrix constructed by adding currencies one by one or by merging by blocks returns
   * the same result.
   */
  public void merge2() {
    final FXMatrix fxMatrix1 = new FXMatrix();
    fxMatrix1.addCurrency(EUR, USD, EUR_USD);
    fxMatrix1.addCurrency(KRW, USD, 1.0 / USD_KRW);
    final FXMatrix fxMatrix2 = new FXMatrix();
    fxMatrix2.addCurrency(EUR, USD, EUR_USD);
    fxMatrix2.addCurrency(GBP, EUR, GBP_EUR);
    final FXMatrix fxMatrixMergeExpected = new FXMatrix();
    fxMatrixMergeExpected.addCurrency(EUR, USD, EUR_USD);
    fxMatrixMergeExpected.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrixMergeExpected.addCurrency(KRW, USD, 1.0 / USD_KRW);
    final FXMatrix merged = FXMatrixUtils.merge(fxMatrix1, fxMatrix2);
    assertEquals(
        "FXMatrixUtils - merge",
        merged.getFxRate(USD, EUR),
        fxMatrixMergeExpected.getFxRate(USD, EUR),
        TOLERANCE_RATE);
    assertEquals(
        "FXMatrixUtils - merge",
        merged.getFxRate(USD, GBP),
        fxMatrixMergeExpected.getFxRate(USD, GBP),
        TOLERANCE_RATE);
    assertEquals(
        "FXMatrixUtils - merge",
        merged.getFxRate(USD, KRW),
        fxMatrixMergeExpected.getFxRate(USD, KRW),
        TOLERANCE_RATE);
  }

  @Test
  /** Tests the merge with an empty matrix. */
  public void merge3() {
    final FXMatrix fxMatrix1 = new FXMatrix();
    fxMatrix1.addCurrency(EUR, USD, EUR_USD);
    fxMatrix1.addCurrency(KRW, USD, 1.0 / USD_KRW);
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrix1, FXMatrixUtils.merge(fxMatrix1, new FXMatrix()), TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrix1, FXMatrixUtils.merge(new FXMatrix(), fxMatrix1), TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            fxMatrix1, FXMatrixUtils.merge(new FXMatrix(USD), fxMatrix1), TOLERANCE_RATE));
    assertTrue(
        "FXMatrixUtils - merge",
        FXMatrixUtils.compare(
            new FXMatrix(), FXMatrixUtils.merge(new FXMatrix(), new FXMatrix()), TOLERANCE_RATE));
  }

  @Test
  /** Tests the comparison tool. */
  public void compare() {
    // Matrix with itself
    final FXMatrix fxMatrix1 = new FXMatrix();
    fxMatrix1.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix1.addCurrency(USD, EUR, 1.0d / EUR_USD);
    assertTrue(
        "FXMatrixUtils - compare", FXMatrixUtils.compare(fxMatrix1, fxMatrix1, TOLERANCE_RATE));
    // Matrix in a different order
    final FXMatrix fxMatrix2 = new FXMatrix();
    fxMatrix2.addCurrency(EUR, USD, EUR_USD);
    fxMatrix2.addCurrency(GBP, EUR, GBP_EUR);
    assertTrue(
        "FXMatrixUtils - compare", FXMatrixUtils.compare(fxMatrix1, fxMatrix2, TOLERANCE_RATE));
    // Matrix with different order rate
    final FXMatrix fxMatrix3 = new FXMatrix();
    fxMatrix3.addCurrency(EUR, USD, EUR_USD + 1.0E-5);
    fxMatrix3.addCurrency(GBP, EUR, GBP_EUR);
    assertFalse(
        "FXMatrixUtils - compare", FXMatrixUtils.compare(fxMatrix1, fxMatrix3, TOLERANCE_RATE));
    // Matrix with different currencies
    final FXMatrix fxMatrix4 = new FXMatrix();
    fxMatrix4.addCurrency(GBP, EUR, GBP_EUR);
    fxMatrix4.addCurrency(USD, EUR, 1.0d / EUR_USD);
    fxMatrix4.addCurrency(KRW, USD, 1.0 / USD_KRW);
    assertFalse(
        "FXMatrixUtils - compare", FXMatrixUtils.compare(fxMatrix1, fxMatrix4, TOLERANCE_RATE));
  }
}
    @Override
    public Set<ComputedValue> execute(
        final FunctionExecutionContext executionContext,
        final FunctionInputs inputs,
        final ComputationTarget target,
        final Set<ValueRequirement> desiredValues) {
      final Position position = target.getPosition();
      final ValueRequirement desiredValue = desiredValues.iterator().next();
      final ValueProperties constraints = desiredValue.getConstraints();
      final Set<String> resultCurrencies = constraints.getValues(CURRENCY);
      final FXForwardSecurity security = (FXForwardSecurity) position.getSecurity();
      final MultipleCurrencyAmount mca =
          (MultipleCurrencyAmount) inputs.getValue(ValueRequirementNames.FX_CURRENCY_EXPOSURE);
      final Currency payCurrency = security.getPayCurrency();
      final Currency receiveCurrency = security.getReceiveCurrency();
      final CurrencyPair currencyPair =
          _currencyPairs.getCurrencyPair(payCurrency, receiveCurrency);
      final Currency baseCurrency = currencyPair.getBase();
      final Currency currencyNonBase = currencyPair.getCounter(); // The non-base currency
      final double exposure = mca.getAmount(currencyNonBase);

      final ValueSpecification spec =
          new ValueSpecification(
              ValueRequirementNames.PNL_SERIES,
              target.toSpecification(),
              desiredValue.getConstraints());
      if (resultCurrencies == null || resultCurrencies.size() != 1) {
        s_logger.warn("No Currency property - returning result in base currency");
        final LocalDateDoubleTimeSeries fxSpotReturnSeries =
            (LocalDateDoubleTimeSeries) inputs.getValue(ValueRequirementNames.RETURN_SERIES);
        final LocalDateDoubleTimeSeries pnlSeries =
            fxSpotReturnSeries.multiply(
                position.getQuantity().doubleValue()
                    * exposure); // The P/L time series is in the base currency
        return Collections.singleton(new ComputedValue(spec, pnlSeries));
      }
      final Currency resultCurrency = Currency.of(Iterables.getOnlyElement(resultCurrencies));
      final LocalDateDoubleTimeSeries conversionTS =
          (LocalDateDoubleTimeSeries) inputs.getValue(HISTORICAL_FX_TIME_SERIES);
      if (conversionTS == null) {
        throw new OpenGammaRuntimeException(
            "Asked for result in "
                + resultCurrency
                + " but could not get "
                + baseCurrency
                + "/"
                + resultCurrency
                + " conversion series");
      }
      if (resultCurrency.equals(baseCurrency)) {
        final LocalDateDoubleTimeSeries fxSpotReturnSeries =
            (LocalDateDoubleTimeSeries) inputs.getValue(ValueRequirementNames.RETURN_SERIES);
        final LocalDateDoubleTimeSeries convertedSeries =
            conversionTS
                .reciprocal()
                .multiply(
                    position.getQuantity().doubleValue()
                        * exposure); // The P/L time series is in the base currency
        final LocalDateDoubleTimeSeries pnlSeries =
            fxSpotReturnSeries.multiply(
                convertedSeries); // The P/L time series is in the base currency
        return Collections.singleton(new ComputedValue(spec, pnlSeries));
      }
      final LocalDateDoubleTimeSeries fxSpotReturnSeries =
          (LocalDateDoubleTimeSeries) inputs.getValue(ValueRequirementNames.RETURN_SERIES);
      final LocalDateDoubleTimeSeries convertedSeries =
          conversionTS.multiply(
              position.getQuantity().doubleValue()
                  * exposure); // The P/L time series is in the base currency
      final LocalDateDoubleTimeSeries pnlSeries = convertedSeries.multiply(fxSpotReturnSeries);
      return Collections.singleton(new ComputedValue(spec, pnlSeries));
    }
 @Override
 public IndexPrice buildObject(final FudgeDeserializer deserializer, final FudgeMsg message) {
   final String name = message.getString(NAME_FIELD);
   final Currency currency = Currency.of(message.getString(CURRENCY_FIELD));
   return new IndexPrice(name, currency);
 }