//-------------------------------------------------------------------------
        // accrual schedule
        private static PeriodicSchedule parseAccrualSchedule(CsvRow row, string leg)
        {
            PeriodicSchedule.Builder builder = PeriodicSchedule.builder();
            // basics
            builder.startDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, START_DATE_FIELD)));
            builder.endDate(LoaderUtils.parseDate(getValueWithFallback(row, leg, END_DATE_FIELD)));
            builder.frequency(Frequency.parse(getValue(row, leg, FREQUENCY_FIELD)));
            // adjustments
            BusinessDayAdjustment            dateAdj      = parseBusinessDayAdjustment(row, leg, DATE_ADJ_CNV_FIELD, DATE_ADJ_CAL_FIELD).orElse(BusinessDayAdjustment.NONE);
            Optional <BusinessDayAdjustment> startDateAdj = parseBusinessDayAdjustment(row, leg, START_DATE_CNV_FIELD, START_DATE_CAL_FIELD);
            Optional <BusinessDayAdjustment> endDateAdj   = parseBusinessDayAdjustment(row, leg, END_DATE_CNV_FIELD, END_DATE_CAL_FIELD);

            builder.businessDayAdjustment(dateAdj);
            if (startDateAdj.Present && !startDateAdj.get().Equals(dateAdj))
            {
                builder.startDateBusinessDayAdjustment(startDateAdj.get());
            }
            if (endDateAdj.Present && !endDateAdj.get().Equals(dateAdj))
            {
                builder.endDateBusinessDayAdjustment(endDateAdj.get());
            }
            // optionals
            builder.stubConvention(findValueWithFallback(row, leg, STUB_CONVENTION_FIELD).map(s => StubConvention.of(s)).orElse(StubConvention.SMART_INITIAL));
            findValue(row, leg, ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s)).ifPresent(v => builder.rollConvention(v));
            findValue(row, leg, FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.firstRegularStartDate(v));
            findValue(row, leg, LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(s)).ifPresent(v => builder.lastRegularEndDate(v));
            parseAdjustableDate(row, leg, OVERRIDE_START_DATE_FIELD, OVERRIDE_START_DATE_CNV_FIELD, OVERRIDE_START_DATE_CAL_FIELD).ifPresent(d => builder.overrideStartDate(d));
            return(builder.build());
        }
        // parse a trade based on a convention
        internal static SwapTrade parseWithConvention(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver, string conventionStr)
        {
            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 <Period>            periodToStartOpt     = row.findValue(PERIOD_TO_START_FIELD).map(s => LoaderUtils.parsePeriod(s));
            Optional <Tenor>             tenorOpt             = row.findValue(TENOR_FIELD).map(s => LoaderUtils.parseTenor(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 <RollConvention>    rollCnvOpt           = row.findValue(ROLL_CONVENTION_FIELD).map(s => LoaderUtils.parseRollConvention(s));
            Optional <StubConvention>    stubCnvOpt           = row.findValue(STUB_CONVENTION_FIELD).map(s => StubConvention.of(s));
            Optional <LocalDate>         firstRegStartDateOpt = row.findValue(FIRST_REGULAR_START_DATE_FIELD).map(s => LoaderUtils.parseDate(s));
            Optional <LocalDate>         lastRegEndDateOpt    = row.findValue(LAST_REGULAR_END_DATE_FIELD).map(s => LoaderUtils.parseDate(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));
            double?                      fxRateOpt            = row.findValue(FX_RATE_FIELD).map(str => LoaderUtils.parseDouble(str));

            // explicit dates take precedence over relative ones
            if (startDateOpt.Present && endDateOpt.Present)
            {
                if (periodToStartOpt.Present || tenorOpt.Present)
                {
                    throw new System.ArgumentException("Swap 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, TENOR_FIELD));
                }
                LocalDate startDate = startDateOpt.get();
                LocalDate endDate   = endDateOpt.get();
                SwapTrade trade     = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt);
                return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
            }

            // start date + tenor
            if (startDateOpt.Present && tenorOpt.Present)
            {
                if (periodToStartOpt.Present || endDateOpt.Present)
                {
                    throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " then these fields must not be present " + ImmutableList.of(PERIOD_TO_START_FIELD, END_DATE_FIELD));
                }
                LocalDate startDate = startDateOpt.get();
                Tenor     tenor     = tenorOpt.get();
                LocalDate endDate   = startDate.plus(tenor);
                SwapTrade trade     = createSwap(info, conventionStr, startDate, endDate, buySell, notional, fixedRate, fxRateOpt);
                return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
            }

            // relative dates
            if (periodToStartOpt.Present && tenorOpt.Present && info.TradeDate.Present)
            {
                if (startDateOpt.Present || endDateOpt.Present)
                {
                    throw new System.ArgumentException("Swap trade had invalid combination of fields. When these fields are found " + ImmutableList.of(CONVENTION_FIELD, PERIOD_TO_START_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 = periodToStartOpt.get();
                Tenor     tenor         = tenorOpt.get();
                if (fxRateOpt.HasValue)
                {
                    XCcyIborIborSwapConvention convention = XCcyIborIborSwapConvention.of(conventionStr);
                    double    notionalFlat = notional * fxRateOpt.Value;
                    SwapTrade trade        = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, notionalFlat, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
                }
                else
                {
                    SingleCurrencySwapConvention convention = SingleCurrencySwapConvention.of(conventionStr);
                    SwapTrade trade = convention.createTrade(tradeDate, periodToStart, tenor, buySell, notional, fixedRate, resolver.ReferenceData);
                    trade = trade.toBuilder().info(info).build();
                    return(adjustTrade(trade, rollCnvOpt, stubCnvOpt, firstRegStartDateOpt, lastRegEndDateOpt, dateCnv, dateCalOpt));
                }
            }

            // no match
            throw new System.ArgumentException("Swap 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, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, TENOR_FIELD) + " or " + ImmutableList.of(CONVENTION_FIELD, START_DATE_FIELD, END_DATE_FIELD));
        }