// convention-based // ideally we'd use the trade date plus "period to start" to get the spot/payment date // but we don't have all the data and it gets complicated in places like TRY, RUB and AED private static FxSingleTrade parseConvention(CsvRow row, TradeInfo info) { CurrencyPair pair = CurrencyPair.parse(row.getValue(CONVENTION_FIELD)); BuySell buySell = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD)); Currency currency = Currency.parse(row.getValue(CURRENCY_FIELD)); double notional = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD)); double fxRate = LoaderUtils.parseDouble(row.getValue(FX_RATE_FIELD)); LocalDate paymentDate = LoaderUtils.parseDate(row.getValue(PAYMENT_DATE_FIELD)); Optional <BusinessDayAdjustment> paymentAdj = parsePaymentDateAdjustment(row); CurrencyAmount amount = CurrencyAmount.of(currency, buySell.normalize(notional)); FxSingle fx = paymentAdj.map(adj => FxSingle.of(amount, FxRate.of(pair, fxRate), paymentDate, adj)).orElseGet(() => FxSingle.of(amount, FxRate.of(pair, fxRate), paymentDate)); return(FxSingleTrade.of(info, fx)); }
private FxSingle parseLeg(XmlElement legEl, FpmlDocument document, TradeInfoBuilder tradeInfoBuilder) { // supported elements: // 'exchangedCurrency1/paymentAmount' // 'exchangedCurrency2/paymentAmount' // 'valueDate' // ignored elements: // 'dealtCurrency?' // 'exchangeRate' // rejected elements: // 'nonDeliverableSettlement?' // 'currency1ValueDate' // 'currency2ValueDate' document.validateNotPresent(legEl, "currency1ValueDate"); document.validateNotPresent(legEl, "currency2ValueDate"); document.validateNotPresent(legEl, "nonDeliverableSettlement"); XmlElement curr1El = legEl.getChild("exchangedCurrency1"); XmlElement curr2El = legEl.getChild("exchangedCurrency2"); // pay/receive and counterparty PayReceive curr1PayReceive = document.parsePayerReceiver(curr1El, tradeInfoBuilder); PayReceive curr2PayReceive = document.parsePayerReceiver(curr2El, tradeInfoBuilder); if (curr1PayReceive == curr2PayReceive) { throw new FpmlParseException("FX single leg currencies must not have same Pay/Receive direction"); } // amount CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); curr2Amount = curr2Amount.positive(); } else { curr1Amount = curr1Amount.positive(); curr2Amount = curr2Amount.negative(); } // payment date LocalDate valueDate = document.parseDate(legEl.getChild("valueDate")); // result return(FxSingle.of(curr1Amount, curr2Amount, valueDate)); }
// parse an FxSingle internal static FxSingle parseFxSingle(CsvRow row, string prefix) { PayReceive direction1 = LoaderUtils.parsePayReceive(row.getValue(prefix + LEG_1_DIRECTION_FIELD)); Currency currency1 = Currency.of(row.getValue(prefix + LEG_1_CURRENCY_FIELD)); double notional1 = LoaderUtils.parseDouble(row.getValue(prefix + LEG_1_NOTIONAL_FIELD)); LocalDate paymentDate1 = row.findValue(prefix + LEG_1_PAYMENT_DATE_FIELD).map(str => LoaderUtils.parseDate(str)).orElseGet(() => LoaderUtils.parseDate(row.getValue(prefix + PAYMENT_DATE_FIELD))); PayReceive direction2 = LoaderUtils.parsePayReceive(row.getValue(prefix + LEG_2_DIRECTION_FIELD)); Currency currency2 = Currency.of(row.getValue(prefix + LEG_2_CURRENCY_FIELD)); double notional2 = LoaderUtils.parseDouble(row.getValue(prefix + LEG_2_NOTIONAL_FIELD)); LocalDate paymentDate2 = row.findValue(prefix + LEG_2_PAYMENT_DATE_FIELD).map(str => LoaderUtils.parseDate(str)).orElseGet(() => LoaderUtils.parseDate(row.getValue(prefix + PAYMENT_DATE_FIELD))); Optional <BusinessDayAdjustment> paymentAdj = parsePaymentDateAdjustment(row); if (direction1.Equals(direction2)) { throw new System.ArgumentException(Messages.format("FxSingle legs must not have the same direction: {}, {}", direction1.ToString(), direction2.ToString())); } Payment payment1 = Payment.of(currency1, direction1.normalize(notional1), paymentDate1); Payment payment2 = Payment.of(currency2, direction2.normalize(notional2), paymentDate2); return(paymentAdj.map(adj => FxSingle.of(payment1, payment2, adj)).orElseGet(() => FxSingle.of(payment1, payment2))); }
internal static FxVanillaOption sut2() { FxSingle fxProduct = FxSingle.of(CurrencyAmount.of(EUR, -NOTIONAL), CurrencyAmount.of(GBP, NOTIONAL * 0.9), PAYMENT_DATE); return(FxVanillaOption.builder().longShort(LongShort.SHORT).expiryDate(LocalDate.of(2015, 2, 15)).expiryTime(LocalTime.of(12, 45)).expiryZone(ZoneId.of("GMT")).underlying(fxProduct).build()); }
//------------------------------------------------------------------------- public Trade parseTrade(FpmlDocument document, XmlElement tradeEl) { // supported elements: // 'exchangedCurrency1/paymentAmount' // 'exchangedCurrency2/paymentAmount' // 'valueDate' // 'currency1ValueDate' // 'currency2ValueDate' // 'nonDeliverableSettlement?' // ignored elements: // 'dealtCurrency?' // 'exchangeRate' XmlElement fxEl = tradeEl.getChild("fxSingleLeg"); // amounts TradeInfoBuilder tradeInfoBuilder = document.parseTradeInfo(tradeEl); XmlElement curr1El = fxEl.getChild("exchangedCurrency1"); XmlElement curr2El = fxEl.getChild("exchangedCurrency2"); // pay/receive and counterparty PayReceive curr1PayReceive = document.parsePayerReceiver(curr1El, tradeInfoBuilder); PayReceive curr2PayReceive = document.parsePayerReceiver(curr2El, tradeInfoBuilder); if (curr1PayReceive == curr2PayReceive) { throw new FpmlParseException("FX single leg currencies must not have same Pay/Receive direction"); } // amount CurrencyAmount curr1Amount = document.parseCurrencyAmount(curr1El.getChild("paymentAmount")); CurrencyAmount curr2Amount = document.parseCurrencyAmount(curr2El.getChild("paymentAmount")); if (curr1PayReceive == PayReceive.PAY) { curr1Amount = curr1Amount.negative(); curr2Amount = curr2Amount.positive(); } else { curr1Amount = curr1Amount.positive(); curr2Amount = curr2Amount.negative(); } // payment date LocalDate currency1Date = document.parseDate(fxEl.findChild("currency1ValueDate").orElseGet(() => fxEl.getChild("valueDate"))); LocalDate currency2Date = document.parseDate(fxEl.findChild("currency2ValueDate").orElseGet(() => fxEl.getChild("valueDate"))); // FxSingle or NDF Optional <XmlElement> ndfEl = fxEl.findChild("nonDeliverableSettlement"); if (!ndfEl.Present) { return(FxSingleTrade.builder().info(tradeInfoBuilder.build()).product(FxSingle.of(Payment.of(curr1Amount, currency1Date), Payment.of(curr2Amount, currency2Date))).build()); } if (!currency1Date.Equals(currency2Date)) { throw new FpmlParseException("FxNdf only supports a single payment date"); } return(parseNdf(document, fxEl, ndfEl.get(), curr1Amount, curr2Amount, currency1Date, tradeInfoBuilder)); }