Exemplo n.º 1
0
        // parse full definition
        private static FxSwapTrade parseFull(CsvRow row, TradeInfo info)
        {
            FxSingle nearFx = FxSingleTradeCsvLoader.parseFxSingle(row, "");
            FxSingle farFx  = FxSingleTradeCsvLoader.parseFxSingle(row, "Far ");

            return(FxSwapTrade.of(info, FxSwap.of(nearFx, farFx)));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Parses the year-month and variant.
        /// </summary>
        /// <param name="row">  the CSV row to parse </param>
        /// <param name="type">  the ETD type </param>
        /// <returns> the expiry year-month and variant </returns>
        /// <exception cref="IllegalArgumentException"> if the row cannot be parsed </exception>
        public static Pair <YearMonth, EtdVariant> parseEtdVariant(CsvRow row, EtdType type)
        {
            YearMonth yearMonth = LoaderUtils.parseYearMonth(row.getValue(EXPIRY_FIELD));
            int       week      = row.findValue(EXPIRY_WEEK_FIELD).map(s => LoaderUtils.parseInteger(s)).orElse(0);
            int       day       = row.findValue(EXPIRY_DAY_FIELD).map(s => LoaderUtils.parseInteger(s)).orElse(0);
            Optional <EtdSettlementType> settleType = row.findValue(SETTLEMENT_TYPE_FIELD).map(s => parseEtdSettlementType(s));
            Optional <EtdOptionType>     optionType = row.findValue(EXERCISE_STYLE_FIELD).map(s => parseEtdOptionType(s));

            // check valid combinations
            if (!settleType.Present)
            {
                if (day == 0)
                {
                    if (week == 0)
                    {
                        return(Pair.of(yearMonth, EtdVariant.ofMonthly()));
                    }
                    else
                    {
                        return(Pair.of(yearMonth, EtdVariant.ofWeekly(week)));
                    }
                }
                else
                {
                    if (week == 0)
                    {
                        return(Pair.of(yearMonth, EtdVariant.ofDaily(day)));
                    }
                    else
                    {
                        throw new System.ArgumentException("ETD date columns conflict, cannot set both expiry day and expiry week");
                    }
                }
            }
            else
            {
                if (day == 0)
                {
                    throw new System.ArgumentException("ETD date columns conflict, must set expiry day for Flex " + type);
                }
                if (week != 0)
                {
                    throw new System.ArgumentException("ETD date columns conflict, cannot set expiry week for Flex " + type);
                }
                if (type == EtdType.FUTURE)
                {
                    return(Pair.of(yearMonth, EtdVariant.ofFlexFuture(day, settleType.get())));
                }
                else
                {
                    if (!optionType.Present)
                    {
                        throw new System.ArgumentException("ETD option type not found for Flex Option");
                    }
                    return(Pair.of(yearMonth, EtdVariant.ofFlexOption(day, settleType.get(), optionType.get())));
                }
            }
        }
        // parses a SecurityTrade from the CSV row
        private static SecurityTrade parseSecurityTrade(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            string     securityIdScheme = row.findValue(SECURITY_ID_SCHEME_FIELD).orElse(DEFAULT_SECURITY_SCHEME);
            string     securityIdValue  = row.getValue(SECURITY_ID_FIELD);
            SecurityId securityId       = SecurityId.of(securityIdScheme, securityIdValue);
            double     price            = LoaderUtils.parseDouble(row.getValue(PRICE_FIELD));
            double     quantity         = parseTradeQuantity(row);

            return(SecurityTrade.of(info, securityId, quantity, price));
        }
        // parses the base SecurityPosition
        internal static SecurityPosition parseSecurityPosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver)
        {
            string           securityIdScheme = row.findValue(SECURITY_ID_SCHEME_FIELD).orElse(DEFAULT_SECURITY_SCHEME);
            string           securityIdValue  = row.getValue(SECURITY_ID_FIELD);
            SecurityId       securityId       = SecurityId.of(securityIdScheme, securityIdValue);
            DoublesPair      quantity         = CsvLoaderUtils.parseQuantity(row);
            SecurityPosition position         = SecurityPosition.ofLongShort(info, securityId, quantity.First, quantity.Second);

            return(resolver.completePosition(row, position));
        }
        // parses the trade quantity, considering the optional buy/sell field
        private static double parseTradeQuantity(CsvRow row)
        {
            double             quantity   = LoaderUtils.parseDouble(row.getValue(QUANTITY_FIELD));
            Optional <BuySell> buySellOpt = row.findValue(BUY_SELL_FIELD).map(str => LoaderUtils.parseBuySell(str));

            if (buySellOpt.Present)
            {
                quantity = buySellOpt.get().normalize(quantity);
            }
            return(quantity);
        }
 // parses the trade
 private static FxSingleTrade parseRow(CsvRow row, TradeInfo info)
 {
     if (row.findValue(CONVENTION_FIELD).Present || row.findValue(BUY_SELL_FIELD).Present)
     {
         return(parseConvention(row, info));
     }
     else
     {
         return(parseFull(row, info));
     }
 }
        // 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));
        }
        // parses the additional GenericSecurityPosition information
        internal static Position parseNonEtdPosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver)
        {
            SecurityPosition    @base        = parseSecurityPosition(row, info, resolver);
            double?             tickSizeOpt  = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str));
            Optional <Currency> currencyOpt  = row.findValue(CURRENCY).map(str => Currency.of(str));
            double?             tickValueOpt = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str));
            double              contractSize = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d);

            if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue)
            {
                SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize);
                GenericSecurity   sec       = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo));
                return(GenericSecurityPosition.ofLongShort(@base.Info, sec, @base.LongQuantity, @base.ShortQuantity));
            }
            return(@base);
        }
        // parses a trade from the CSV row
        internal static SecurityQuantityTrade parseTrade(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            SecurityTrade trade = parseSecurityTrade(row, info, resolver);
            SecurityTrade @base = resolver.completeTrade(row, trade);

            double?tickSizeOpt = row.findValue(TICK_SIZE).map(str => LoaderUtils.parseDouble(str));
            Optional <Currency> currencyOpt = row.findValue(CURRENCY).map(str => Currency.of(str));
            double?tickValueOpt             = row.findValue(TICK_VALUE).map(str => LoaderUtils.parseDouble(str));
            double contractSize             = row.findValue(CONTRACT_SIZE).map(str => LoaderUtils.parseDouble(str)).orElse(1d);

            if (tickSizeOpt.HasValue && currencyOpt.Present && tickValueOpt.HasValue)
            {
                SecurityPriceInfo priceInfo = SecurityPriceInfo.of(tickSizeOpt.Value, CurrencyAmount.of(currencyOpt.get(), tickValueOpt.Value), contractSize);
                GenericSecurity   sec       = GenericSecurity.of(SecurityInfo.of(@base.SecurityId, priceInfo));
                return(GenericSecurityTrade.of(@base.Info, sec, @base.Quantity, @base.Price));
            }
            return(@base);
        }
 //-------------------------------------------------------------------------
 // parses a position from the CSV row
 internal static Position parsePosition(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver)
 {
     if (row.findValue(EXPIRY_FIELD).Present)
     {
         // etd
         if (row.findValue(PUT_CALL_FIELD).Present || row.findValue(EXERCISE_PRICE_FIELD).Present)
         {
             return(resolver.parseEtdOptionPosition(row, info));
         }
         else
         {
             return(resolver.parseEtdFuturePosition(row, info));
         }
     }
     else
     {
         return(parseNonEtdPosition(row, info, resolver));
     }
 }
        // parses the payment date adjustment, which consists of two linked optional fields
        internal static Optional <BusinessDayAdjustment> parsePaymentDateAdjustment(CsvRow row)
        {
            Optional <BusinessDayAdjustment> paymentAdj = null;
            Optional <string> paymentDateCnv            = row.findValue(PAYMENT_DATE_CNV_FIELD); // Optional field with Business day adjustment

            if (paymentDateCnv.Present)
            {
                BusinessDayConvention bdCnv = LoaderUtils.parseBusinessDayConvention(paymentDateCnv.get());
                if (!bdCnv.Equals(BusinessDayConventions.NO_ADJUST))
                {
                    Optional <string> paymentDateCalOpt = row.findValue(PAYMENT_DATE_CAL_FIELD);
                    if (paymentDateCalOpt.Present)
                    {
                        paymentAdj = BusinessDayAdjustment.of(LoaderUtils.parseBusinessDayConvention(paymentDateCnv.get()), HolidayCalendarId.of(paymentDateCalOpt.get()));
                    }
                }
            }
            return(paymentAdj);
        }
 // parses a SecurityPosition from the CSV row, converting ETD information
 internal static SecurityPosition parsePositionLightweight(CsvRow row, PositionInfo info, PositionCsvInfoResolver resolver)
 {
     if (row.findValue(EXPIRY_FIELD).Present)
     {
         // etd
         if (row.findValue(PUT_CALL_FIELD).Present || row.findValue(EXERCISE_PRICE_FIELD).Present)
         {
             return(resolver.parseEtdOptionSecurityPosition(row, info));
         }
         else
         {
             return(resolver.parseEtdFutureSecurityPosition(row, info));
         }
     }
     else
     {
         // simple
         return(parseSecurityPosition(row, info, resolver));
     }
 }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Parses the quantity.
        /// </summary>
        /// <param name="row">  the CSV row to parse </param>
        /// <returns> the quantity, long first, short second </returns>
        /// <exception cref="IllegalArgumentException"> if the row cannot be parsed </exception>
        public static DoublesPair parseQuantity(CsvRow row)
        {
            double?quantityOpt = row.findValue(QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s));

            if (quantityOpt.HasValue)
            {
                double quantity = quantityOpt.Value;
                return(DoublesPair.of(quantity >= 0 ? quantity : 0, quantity >= 0 ? 0 : -quantity));
            }
            double?longQuantityOpt  = row.findValue(LONG_QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s));
            double?shortQuantityOpt = row.findValue(SHORT_QUANTITY_FIELD).map(s => LoaderUtils.parseDouble(s));

            if (!longQuantityOpt.HasValue && !shortQuantityOpt.HasValue)
            {
                throw new System.ArgumentException(Messages.format("Security must contain a quantity column, either '{}' or '{}' and '{}'", QUANTITY_FIELD, LONG_QUANTITY_FIELD, SHORT_QUANTITY_FIELD));
            }
            double longQuantity  = ArgChecker.notNegative(longQuantityOpt.GetValueOrDefault(0d), LONG_QUANTITY_FIELD);
            double shortQuantity = ArgChecker.notNegative(shortQuantityOpt.GetValueOrDefault(0d), SHORT_QUANTITY_FIELD);

            return(DoublesPair.of(longQuantity, shortQuantity));
        }
        // 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)));
        }
Exemplo n.º 15
0
        // parse the row to a trade
        private static FraTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            BuySell buySell   = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD));
            double  notional  = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD));
            double  fixedRate = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD));
            Optional <FraConvention>     conventionOpt    = row.findValue(CONVENTION_FIELD).map(s => FraConvention.of(s));
            Optional <Period>            periodToStartOpt = row.findValue(PERIOD_TO_START_FIELD).map(s => LoaderUtils.parsePeriod(s));
            Optional <LocalDate>         startDateOpt     = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <LocalDate>         endDateOpt       = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <IborIndex>         indexOpt         = row.findValue(INDEX_FIELD).map(s => IborIndex.of(s));
            Optional <IborIndex>         interpolatedOpt  = row.findValue(INTERPOLATED_INDEX_FIELD).map(s => IborIndex.of(s));
            Optional <DayCount>          dayCountOpt      = row.findValue(DAY_COUNT_FIELD).map(s => LoaderUtils.parseDayCount(s));
            BusinessDayConvention        dateCnv          = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING);
            Optional <HolidayCalendarId> dateCalOpt       = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s));

            // not parsing paymentDate, fixingDateOffset, discounting

            // use convention if available
            if (conventionOpt.Present)
            {
                if (indexOpt.Present || interpolatedOpt.Present || dayCountOpt.Present)
                {
                    throw new System.ArgumentException("Fra trade had invalid combination of fields. When '" + CONVENTION_FIELD + "' is present these fields must not be present: " + ImmutableList.of(INDEX_FIELD, INTERPOLATED_INDEX_FIELD, DAY_COUNT_FIELD));
                }
                FraConvention convention = conventionOpt.get();
                // explicit dates take precedence over relative ones
                if (startDateOpt.Present && endDateOpt.Present)
                {
                    if (periodToStartOpt.Present)
                    {
                        throw new System.ArgumentException("Fra trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD));
                    }
                    LocalDate startDate = startDateOpt.get();
                    LocalDate endDate   = endDateOpt.get();
                    // NOTE: payment date assumed to be the start date
                    FraTrade trade = convention.toTrade(info, startDate, endDate, startDate, buySell, notional, fixedRate);
                    return(adjustTrade(trade, dateCnv, dateCalOpt));
                }
                // relative dates
                if (periodToStartOpt.Present && info.TradeDate.Present)
                {
                    if (startDateOpt.Present || endDateOpt.Present)
                    {
                        throw new System.ArgumentException("Fra trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, PERIOD_TO_START_FIELD, TRADE_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD));
                    }
                    LocalDate tradeDate     = info.TradeDate.get();
                    Period    periodToStart = periodToStartOpt.get();
                    FraTrade  trade         = convention.createTrade(tradeDate, periodToStart, buySell, notional, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, dateCnv, dateCalOpt));
                }
            }
            else if (startDateOpt.Present && endDateOpt.Present && indexOpt.Present)
            {
                LocalDate   startDate = startDateOpt.get();
                LocalDate   endDate   = endDateOpt.get();
                IborIndex   index     = indexOpt.get();
                Fra.Builder builder   = Fra.builder().buySell(buySell).notional(notional).startDate(startDate).endDate(endDate).fixedRate(fixedRate).index(index);
                interpolatedOpt.ifPresent(interpolated => builder.indexInterpolated(interpolated));
                dayCountOpt.ifPresent(dayCount => builder.dayCount(dayCount));
                return(adjustTrade(FraTrade.of(info, builder.build()), dateCnv, dateCalOpt));
            }
            // no match
            throw new System.ArgumentException("Fra trade had invalid combination of fields. These fields are mandatory:" + ImmutableList.of(BUY_SELL_FIELD, NOTIONAL_FIELD, FIXED_RATE_FIELD) + " and one of these combinations is mandatory: " + ImmutableList.of(CONVENTION_FIELD, TRADE_DATE_FIELD, PERIOD_TO_START_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " or " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD, INDEX_FIELD));
        }
        /// <summary>
        /// Parses the data from a CSV row.
        /// </summary>
        /// <param name="row">  the CSV row object </param>
        /// <param name="info">  the trade info object </param>
        /// <param name="resolver">  the resolver used to parse additional information. This is not currently used in this method. </param>
        /// <returns> the parsed trade, as an instance of <seealso cref="FxSingleTrade"/> </returns>
        internal static FxSingleTrade parse(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            FxSingleTrade trade = parseRow(row, info);

            return(resolver.completeTrade(row, trade));
        }
        // parse full definition
        private static FxSingleTrade parseFull(CsvRow row, TradeInfo info)
        {
            FxSingle fx = parseFxSingle(row, "");

            return(FxSingleTrade.of(info, fx));
        }
        // parse the row to a trade
        private static TermDepositTrade parseRow(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            BuySell buySell   = LoaderUtils.parseBuySell(row.getValue(BUY_SELL_FIELD));
            double  notional  = LoaderUtils.parseDouble(row.getValue(NOTIONAL_FIELD));
            double  fixedRate = LoaderUtils.parseDoublePercent(row.getValue(FIXED_RATE_FIELD));
            Optional <TermDepositConvention> conventionOpt = row.findValue(CONVENTION_FIELD).map(s => TermDepositConvention.of(s));
            Optional <Period>            tenorOpt          = row.findValue(TENOR_FIELD).map(s => LoaderUtils.parseTenor(s).Period);
            Optional <LocalDate>         startDateOpt      = row.findValue(START_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <LocalDate>         endDateOpt        = row.findValue(END_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <Currency>          currencyOpt       = row.findValue(CURRENCY_FIELD).map(s => Currency.parse(s));
            Optional <DayCount>          dayCountOpt       = row.findValue(DAY_COUNT_FIELD).map(s => LoaderUtils.parseDayCount(s));
            BusinessDayConvention        dateCnv           = row.findValue(DATE_ADJ_CNV_FIELD).map(s => LoaderUtils.parseBusinessDayConvention(s)).orElse(BusinessDayConventions.MODIFIED_FOLLOWING);
            Optional <HolidayCalendarId> dateCalOpt        = row.findValue(DATE_ADJ_CAL_FIELD).map(s => HolidayCalendarId.of(s));

            // use convention if available
            if (conventionOpt.Present)
            {
                if (currencyOpt.Present || dayCountOpt.Present)
                {
                    throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. When '" + CONVENTION_FIELD + "' is present these fields must not be present: " + ImmutableList.of(CURRENCY_FIELD, DAY_COUNT_FIELD));
                }
                TermDepositConvention convention = conventionOpt.get();
                // explicit dates take precedence over relative ones
                if (startDateOpt.Present && endDateOpt.Present)
                {
                    if (tenorOpt.Present)
                    {
                        throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(TENOR_FIELD));
                    }
                    LocalDate        startDate = startDateOpt.get();
                    LocalDate        endDate   = endDateOpt.get();
                    TermDepositTrade trade     = convention.toTrade(info, startDate, endDate, buySell, notional, fixedRate);
                    return(adjustTrade(trade, dateCnv, dateCalOpt));
                }
                // relative dates
                if (tenorOpt.Present && info.TradeDate.Present)
                {
                    if (startDateOpt.Present || endDateOpt.Present)
                    {
                        throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, TENOR_FIELD, TRADE_DATE_FIELD) + " then these fields must not be present " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD));
                    }
                    LocalDate        tradeDate     = info.TradeDate.get();
                    Period           periodToStart = tenorOpt.get();
                    TermDepositTrade trade         = convention.createTrade(tradeDate, periodToStart, buySell, notional, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, dateCnv, dateCalOpt));
                }
            }
            else if (startDateOpt.Present && endDateOpt.Present && currencyOpt.Present && dayCountOpt.Present)
            {
                LocalDate           startDate = startDateOpt.get();
                LocalDate           endDate   = endDateOpt.get();
                Currency            currency  = currencyOpt.get();
                DayCount            dayCount  = dayCountOpt.get();
                TermDeposit.Builder builder   = TermDeposit.builder().buySell(buySell).currency(currency).notional(notional).startDate(startDate).endDate(endDate).dayCount(dayCount).rate(fixedRate);
                TermDepositTrade    trade     = TermDepositTrade.of(info, builder.build());
                return(adjustTrade(trade, dateCnv, dateCalOpt));
            }
            // no match
            throw new System.ArgumentException("TermDeposit trade had invalid combination of fields. These fields are mandatory:" + ImmutableList.of(BUY_SELL_FIELD, NOTIONAL_FIELD, FIXED_RATE_FIELD) + " and one of these combinations is mandatory: " + ImmutableList.of(CONVENTION_FIELD, TRADE_DATE_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD) + " or " + ImmutableList.of(START_DATE_FIELD, END_DATE_FIELD, CURRENCY_FIELD, DAY_COUNT_FIELD));
        }
        /// <summary>
        /// Parses from the CSV row.
        /// </summary>
        /// <param name="row">  the CSV row </param>
        /// <param name="info">  the trade info </param>
        /// <param name="resolver">  the resolver used to parse additional information </param>
        /// <returns> the parsed trade </returns>
        internal static TermDepositTrade parse(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver)
        {
            TermDepositTrade trade = parseRow(row, info, resolver);

            return(resolver.completeTrade(row, trade));
        }