public virtual void test_resolve()
        {
            BusinessDayAdjustment bussAdj = BusinessDayAdjustment.of(FOLLOWING, SAT_SUN);
            ResolvedCds           test    = PRODUCT_STD.resolve(REF_DATA);
            int nDates = 44;

            LocalDate[] dates = new LocalDate[nDates];
            for (int i = 0; i < nDates; ++i)
            {
                dates[i] = START_DATE.plusMonths(3 * i);
            }
            IList <CreditCouponPaymentPeriod> payments = new List <CreditCouponPaymentPeriod>(nDates - 1);

            for (int i = 0; i < nDates - 2; ++i)
            {
                LocalDate start = i == 0 ? dates[i] : bussAdj.adjust(dates[i], REF_DATA);
                LocalDate end   = bussAdj.adjust(dates[i + 1], REF_DATA);
                payments.Add(CreditCouponPaymentPeriod.builder().startDate(start).endDate(end).unadjustedStartDate(dates[i]).unadjustedEndDate(dates[i + 1]).effectiveStartDate(start.minusDays(1)).effectiveEndDate(end.minusDays(1)).paymentDate(end).currency(USD).notional(NOTIONAL).fixedRate(COUPON).yearFraction(ACT_360.relativeYearFraction(start, end)).build());
            }
            LocalDate start = bussAdj.adjust(dates[nDates - 2], REF_DATA);
            LocalDate end   = dates[nDates - 1];

            payments.Add(CreditCouponPaymentPeriod.builder().startDate(start).endDate(end.plusDays(1)).unadjustedStartDate(dates[nDates - 2]).unadjustedEndDate(end).effectiveStartDate(start.minusDays(1)).effectiveEndDate(end).paymentDate(bussAdj.adjust(end, REF_DATA)).currency(USD).notional(NOTIONAL).fixedRate(COUPON).yearFraction(ACT_360.relativeYearFraction(start, end.plusDays(1))).build());
            ResolvedCds expected = ResolvedCds.builder().buySell(BUY).legalEntityId(LEGAL_ENTITY).dayCount(ACT_360).paymentOnDefault(ACCRUED_PREMIUM).paymentPeriods(payments).protectionStart(BEGINNING).protectionEndDate(END_DATE).settlementDateOffset(SETTLE_DAY_ADJ).stepinDateOffset(STEPIN_DAY_ADJ).build();

            assertEquals(test, expected);
        }
        public virtual void test_trade()
        {
            FraCurveNode        node              = FraCurveNode.of(TEMPLATE, QUOTE_ID, SPREAD);
            LocalDate           valuationDate     = LocalDate.of(2015, 1, 22);
            double              rate              = 0.035;
            ImmutableMarketData marketData        = ImmutableMarketData.builder(valuationDate).addValue(QUOTE_ID, rate).build();
            FraTrade            trade             = node.trade(1d, marketData, REF_DATA);
            LocalDate           startDateExpected = BDA_MOD_FOLLOW.adjust(OFFSET.adjust(valuationDate, REF_DATA).plus(PERIOD_TO_START), REF_DATA);
            LocalDate           endDateExpected   = BDA_MOD_FOLLOW.adjust(OFFSET.adjust(valuationDate, REF_DATA).plus(PERIOD_TO_END), REF_DATA);
            Fra       productExpected             = Fra.builder().buySell(BuySell.SELL).currency(GBP).dayCount(ACT_365F).startDate(startDateExpected).endDate(endDateExpected).paymentDate(AdjustableDate.of(startDateExpected)).notional(1.0d).index(GBP_LIBOR_3M).fixedRate(rate + SPREAD).build();
            TradeInfo tradeInfoExpected           = TradeInfo.builder().tradeDate(valuationDate).build();

            assertEquals(trade.Product, productExpected);
            assertEquals(trade.Info, tradeInfoExpected);
        }
            public BasicFixedLeg(IsdaCompliantDiscountCurveCalibrator outerInstance, LocalDate curveSpotDate, LocalDate maturityDate, Period swapInterval, DayCount swapDCC, DayCount curveDcc, BusinessDayAdjustment busAdj, ReferenceData refData)
            {
                this.outerInstance = outerInstance;

                IList <LocalDate> list  = new List <LocalDate>();
                LocalDate         tDate = maturityDate;
                int step = 1;

                while (tDate.isAfter(curveSpotDate))
                {
                    list.Add(tDate);
                    tDate = maturityDate.minus(swapInterval.multipliedBy(step++));
                }

                // remove spotDate from list, if it ends up there
                list.Remove(curveSpotDate);

                nPayment        = list.Count;
                swapPaymentTime = new double[nPayment];
                yearFraction    = new double[nPayment];
                LocalDate prev = curveSpotDate;
                int       j    = nPayment - 1;

                for (int i = 0; i < nPayment; i++, j--)
                {
                    LocalDate current = list[j];
                    LocalDate adjCurr = busAdj.adjust(current, refData);
                    yearFraction[i]    = swapDCC.relativeYearFraction(prev, adjCurr);
                    swapPaymentTime[i] = curveDcc.relativeYearFraction(curveSpotDate, adjCurr);     // Payment times always good business days
                    prev = adjCurr;
                }
            }
        public virtual void test_volatilities()
        {
            BlackFxOptionInterpolatedNodalSurfaceVolatilitiesSpecification @base = BlackFxOptionInterpolatedNodalSurfaceVolatilitiesSpecification.builder().name(VOL_NAME).currencyPair(GBP_USD).dayCount(ACT_365F).nodes(NODES).timeInterpolator(PCHIP).strikeInterpolator(DOUBLE_QUADRATIC).build();
            LocalDate     date       = LocalDate.of(2017, 9, 25);
            ZonedDateTime dateTime   = date.atStartOfDay().atZone(ZoneId.of("Europe/London"));
            DoubleArray   parameters = DoubleArray.of(0.19, 0.15, 0.13, 0.14, 0.14, 0.11, 0.09, 0.09, 0.11, 0.09, 0.07, 0.07);
            BlackFxOptionSurfaceVolatilities computed = @base.volatilities(dateTime, parameters, REF_DATA);
            DaysAdjustment expOffset = DaysAdjustment.ofBusinessDays(-2, NY_LO);

            double[] expiries = new double[STRIKES.Count * TENORS.Count];
            double[] strikes  = new double[STRIKES.Count * TENORS.Count];
            ImmutableList.Builder <ParameterMetadata> paramMetadata = ImmutableList.builder();
            for (int i = 0; i < TENORS.Count; ++i)
            {
                double expiry = ACT_365F.relativeYearFraction(date, expOffset.adjust(BDA.adjust(SPOT_OFFSET.adjust(date, REF_DATA).plus(TENORS[i]), REF_DATA), REF_DATA));
                for (int j = 0; j < STRIKES.Count; ++j)
                {
                    paramMetadata.add(FxVolatilitySurfaceYearFractionParameterMetadata.of(expiry, SimpleStrike.of(STRIKES[j]), GBP_USD));
                    expiries[STRIKES.Count * i + j] = expiry;
                    strikes[STRIKES.Count * i + j]  = STRIKES[j];
                }
            }
            InterpolatedNodalSurface         surface  = InterpolatedNodalSurface.ofUnsorted(Surfaces.blackVolatilityByExpiryStrike(VOL_NAME.Name, ACT_365F).withParameterMetadata(paramMetadata.build()), DoubleArray.ofUnsafe(expiries), DoubleArray.ofUnsafe(strikes), parameters, GridSurfaceInterpolator.of(PCHIP, DOUBLE_QUADRATIC));
            BlackFxOptionSurfaceVolatilities expected = BlackFxOptionSurfaceVolatilities.of(VOL_NAME, GBP_USD, dateTime, surface);

            assertEquals(computed, expected);
        }
        public virtual void test_resolve_cap()
        {
            IborRateCalculation rateCalc = IborRateCalculation.builder().index(EUR_EURIBOR_3M).fixingRelativeTo(FixingRelativeTo.PERIOD_END).fixingDateOffset(EUR_EURIBOR_3M.FixingDateOffset).build();
            IborCapFloorLeg     @base    = IborCapFloorLeg.builder().calculation(rateCalc).capSchedule(CAP).notional(NOTIONAL).paymentDateOffset(PAYMENT_OFFSET).paymentSchedule(SCHEDULE).payReceive(RECEIVE).build();

            LocalDate[] unadjustedDates        = new LocalDate[] { START, START.plusMonths(3), START.plusMonths(6), START.plusMonths(9), START.plusMonths(12) };
            IborCapletFloorletPeriod[] periods = new IborCapletFloorletPeriod[4];
            for (int i = 0; i < 4; ++i)
            {
                LocalDate start        = BUSS_ADJ.adjust(unadjustedDates[i], REF_DATA);
                LocalDate end          = BUSS_ADJ.adjust(unadjustedDates[i + 1], REF_DATA);
                double    yearFraction = EUR_EURIBOR_3M.DayCount.relativeYearFraction(start, end);
                periods[i] = IborCapletFloorletPeriod.builder().caplet(CAP.InitialValue).currency(EUR).startDate(start).endDate(end).unadjustedStartDate(unadjustedDates[i]).unadjustedEndDate(unadjustedDates[i + 1]).paymentDate(PAYMENT_OFFSET.adjust(end, REF_DATA)).notional(NOTIONALS[i]).iborRate(IborRateComputation.of(EUR_EURIBOR_3M, rateCalc.FixingDateOffset.adjust(end, REF_DATA), REF_DATA)).yearFraction(yearFraction).build();
            }
            ResolvedIborCapFloorLeg expected = ResolvedIborCapFloorLeg.builder().capletFloorletPeriods(periods).payReceive(RECEIVE).build();
            ResolvedIborCapFloorLeg computed = @base.resolve(REF_DATA);

            assertEquals(computed, expected);
        }
        public virtual void test_resolve()
        {
            CapitalIndexedBond @base = sut();

            LocalDate[] unAdjDates = new LocalDate[] { LocalDate.of(2008, 1, 13), LocalDate.of(2008, 7, 13), LocalDate.of(2009, 1, 13), LocalDate.of(2009, 7, 13), LocalDate.of(2010, 1, 13) };
            CapitalIndexedBondPaymentPeriod[] periodic = new CapitalIndexedBondPaymentPeriod[4];
            for (int i = 0; i < 4; ++i)
            {
                LocalDate       start      = SCHEDULE_ADJ.adjust(unAdjDates[i], REF_DATA);
                LocalDate       end        = SCHEDULE_ADJ.adjust(unAdjDates[i + 1], REF_DATA);
                LocalDate       detachment = EX_COUPON.adjust(end, REF_DATA);
                RateComputation comp       = RATE_CALC.createRateComputation(end);
                periodic[i] = CapitalIndexedBondPaymentPeriod.builder().currency(USD).startDate(start).endDate(end).unadjustedStartDate(unAdjDates[i]).unadjustedEndDate(unAdjDates[i + 1]).detachmentDate(detachment).realCoupon(COUPONS[i]).rateComputation(comp).notional(NOTIONAL).build();
            }
            CapitalIndexedBondPaymentPeriod nominalExp = periodic[3].withUnitCoupon(periodic[0].StartDate, periodic[0].UnadjustedStartDate);
            ResolvedCapitalIndexedBond      expected   = ResolvedCapitalIndexedBond.builder().securityId(SECURITY_ID).dayCount(ACT_ACT_ISDA).legalEntityId(LEGAL_ENTITY).nominalPayment(nominalExp).periodicPayments(periodic).frequency(SCHEDULE.Frequency).rollConvention(SCHEDULE.calculatedRollConvention()).settlementDateOffset(SETTLE_OFFSET).yieldConvention(US_IL_REAL).rateCalculation(@base.RateCalculation).build();

            assertEquals(@base.resolve(REF_DATA), expected);
        }
        static ResolvedCdsIndexTest()
        {
            int nDates = 44;

            LocalDate[] dates = new LocalDate[nDates];
            for (int i = 0; i < nDates; ++i)
            {
                dates[i] = START_DATE.plusMonths(3 * i);
            }
            for (int i = 0; i < nDates - 2; ++i)
            {
                LocalDate start = i == 0 ? dates[i] : BUSS_ADJ.adjust(dates[i], REF_DATA);
                LocalDate end   = BUSS_ADJ.adjust(dates[i + 1], REF_DATA);
                PAYMENTS.Add(CreditCouponPaymentPeriod.builder().startDate(start).endDate(end).effectiveStartDate(start.minusDays(1)).effectiveEndDate(end.minusDays(1)).paymentDate(end).currency(USD).notional(NOTIONAL).fixedRate(COUPON).yearFraction(ACT_360.relativeYearFraction(start, end)).build());
            }
            LocalDate start = BUSS_ADJ.adjust(dates[nDates - 2], REF_DATA);
            LocalDate end   = dates[nDates - 1];

            PAYMENTS.Add(CreditCouponPaymentPeriod.builder().startDate(start).endDate(end.plusDays(1)).effectiveStartDate(start.minusDays(1)).effectiveEndDate(end).paymentDate(BUSS_ADJ.adjust(end, REF_DATA)).currency(USD).notional(NOTIONAL).fixedRate(COUPON).yearFraction(ACT_360.relativeYearFraction(start, end.plusDays(1))).build());
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Converts an FpML 'AdjustedRelativeDateOffset' to a resolved {@code LocalDate}.
        /// </summary>
        /// <param name="baseEl">  the FpML adjustable date element </param>
        /// <returns> the resolved date </returns>
        /// <exception cref="RuntimeException"> if unable to parse </exception>
        public AdjustableDate parseAdjustedRelativeDateOffset(XmlElement baseEl)
        {
            // FpML content: ('periodMultiplier', 'period', 'dayType?',
            //                'businessDayConvention', 'BusinessCentersOrReference.model?'
            //                'dateRelativeTo', 'adjustedDate', 'relativeDateAdjustments?')
            // The 'adjustedDate' element is ignored
            XmlElement relativeToEl = lookupReference(baseEl.getChild("dateRelativeTo"));
            LocalDate  baseDate;

            if (relativeToEl.hasContent())
            {
                baseDate = parseDate(relativeToEl);
            }
            else if (relativeToEl.Name.Contains("relative"))
            {
                baseDate = parseAdjustedRelativeDateOffset(relativeToEl).Unadjusted;
            }
            else
            {
                throw new FpmlParseException("Unable to resolve 'dateRelativeTo' to a date: " + baseEl.getChild("dateRelativeTo").getAttribute(HREF));
            }
            Period period = parsePeriod(baseEl);
            Optional <XmlElement> dayTypeEl = baseEl.findChild("dayType");
            bool calendarDays          = period.Zero || (dayTypeEl.Present && dayTypeEl.get().Content.Equals("Calendar"));
            BusinessDayAdjustment bda1 = parseBusinessDayAdjustments(baseEl);
            BusinessDayAdjustment bda2 = baseEl.findChild("relativeDateAdjustments").map(el => parseBusinessDayAdjustments(el)).orElse(bda1);
            // interpret and resolve, simple calendar arithmetic or business days
            LocalDate resolvedDate;

            if (period.Years > 0 || period.Months > 0 || calendarDays)
            {
                resolvedDate = bda1.adjust(baseDate.plus(period), refData);
            }
            else
            {
                LocalDate datePlusBusDays = bda1.Calendar.resolve(refData).shift(baseDate, period.Days);
                resolvedDate = bda1.adjust(datePlusBusDays, refData);
            }
            return(AdjustableDate.of(resolvedDate, bda2));
        }
示例#9
0
 static SwaptionCubeData()
 {
     EXPIRIES.Add(Period.ofMonths(1));
     EXPIRIES.Add(Period.ofMonths(3));
     EXPIRIES.Add(Period.ofMonths(6));
     EXPIRIES.Add(Period.ofYears(1));
     EXPIRIES.Add(Period.ofYears(2));
     EXPIRIES.Add(Period.ofYears(5));
     TENORS.Add(Tenor.TENOR_1Y);
     TENORS.Add(Tenor.TENOR_2Y);
     TENORS.Add(Tenor.TENOR_5Y);
     EXPIRIES_SIMPLE.Add(Period.ofMonths(1));
     EXPIRIES_SIMPLE.Add(Period.ofMonths(6));
     EXPIRIES_SIMPLE.Add(Period.ofYears(1));
     TENORS_SIMPLE.Add(Tenor.TENOR_1Y);
     TENORS_SIMPLE.Add(Tenor.TENOR_2Y);
     EXPIRIES_SIMPLE_2.Add(Period.ofMonths(1));
     EXPIRIES_SIMPLE_2.Add(Period.ofMonths(3));
     EXPIRIES_SIMPLE_2.Add(Period.ofMonths(6));
     EXPIRIES_SIMPLE_2.Add(Period.ofYears(1));
     for (int i = 0; i < EXPIRIES_SIMPLE_2.Count; i++)
     {
         BusinessDayAdjustment bda = EUR_FIXED_1Y_EURIBOR_6M.FloatingLeg.StartDateBusinessDayAdjustment;
         EXPIRIES_SIMPLE_2_TIME[2 * i]     = DAY_COUNT.relativeYearFraction(DATA_DATE, bda.adjust(DATA_DATE.plus(EXPIRIES_SIMPLE_2[i]), REF_DATA));
         EXPIRIES_SIMPLE_2_TIME[2 * i + 1] = EXPIRIES_SIMPLE_2_TIME[2 * i];
     }
 }
示例#10
0
        static FxOptionVolatilitiesMarketDataFunctionTest()
        {
            ImmutableList.Builder <FxOptionVolatilitiesNode>        volNodeBuilder             = ImmutableList.builder();
            ImmutableMap.Builder <QuoteId, double>                  marketQuoteBuilder         = ImmutableMap.builder();
            ImmutableMap.Builder <QuoteId, MarketDataBox <double> > scenarioMarketQuoteBuilder = ImmutableMap.builder();
            ImmutableList.Builder <FixedOvernightSwapCurveNode>     usdNodeBuilder             = ImmutableList.builder();
            ImmutableList.Builder <FxSwapCurveNode>                 gbpNodeBuilder             = ImmutableList.builder();
            for (int i = 0; i < VOL_TENORS.Count; ++i)
            {
                for (int j = 0; j < STRIKES.Count; ++j)
                {
                    QuoteId quoteId = QuoteId.of(StandardId.of("OG", VOL_TENORS[i].ToString() + "_" + STRIKES[j].Label + "_" + VALUE_TYPES[j].ToString()));
                    volNodeBuilder.add(FxOptionVolatilitiesNode.of(GBP_USD, SPOT_OFFSET, BDA, VALUE_TYPES[j], quoteId, VOL_TENORS[i], STRIKES[j]));
                    marketQuoteBuilder.put(quoteId, VOL_QUOTES[i][j]);
                    scenarioMarketQuoteBuilder.put(quoteId, MarketDataBox.ofScenarioValues(VOL_QUOTES[i][j], VOL_QUOTES_1[i][j]));
                }
            }
            for (int i = 0; i < USD_QUOTES.Count; ++i)
            {
                QuoteId quoteId = QuoteId.of(StandardId.of("OG", USD.ToString() + "-OIS-" + USD_TENORS[i].ToString()));
                usdNodeBuilder.add(FixedOvernightSwapCurveNode.of(FixedOvernightSwapTemplate.of(USD_TENORS[i], FixedOvernightSwapConventions.USD_FIXED_TERM_FED_FUND_OIS), quoteId));
                marketQuoteBuilder.put(quoteId, USD_QUOTES[i]);
                scenarioMarketQuoteBuilder.put(quoteId, MarketDataBox.ofScenarioValues(USD_QUOTES[i], USD_QUOTES_1[i]));
            }
            for (int i = 0; i < GBP_QUOTES.Count; ++i)
            {
                QuoteId quoteId = QuoteId.of(StandardId.of("OG", GBP_USD.ToString() + "-FX-" + GBP_PERIODS[i].ToString()));
                gbpNodeBuilder.add(FxSwapCurveNode.of(FxSwapTemplate.of(GBP_PERIODS[i], FxSwapConventions.GBP_USD), quoteId));
                marketQuoteBuilder.put(quoteId, GBP_QUOTES[i]);
                scenarioMarketQuoteBuilder.put(quoteId, MarketDataBox.ofScenarioValues(GBP_QUOTES[i], GBP_QUOTES_1[i]));
            }
            VOL_NODES              = volNodeBuilder.build();
            USD_NODES              = usdNodeBuilder.build();
            GBP_NODES              = gbpNodeBuilder.build();
            MARKET_QUOTES          = marketQuoteBuilder.build();
            SCENARIO_MARKET_QUOTES = scenarioMarketQuoteBuilder.build();
            IList <double> expiry  = VOL_TENORS.Select(t => ACT_365F.relativeYearFraction(VALUATION_DATE, BDA.adjust(SPOT_OFFSET.adjust(VALUATION_DATE, REF_DATA).plus(t), REF_DATA))).ToList();
            int            nSmiles = expiry.Count;

            double[] atm = new double[nSmiles];
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] rr = new double[nSmiles][2];
            double[][] rr = RectangularArrays.ReturnRectangularDoubleArray(nSmiles, 2);
//JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java:
//ORIGINAL LINE: double[][] str = new double[nSmiles][2];
            double[][] str = RectangularArrays.ReturnRectangularDoubleArray(nSmiles, 2);
            for (int i = 0; i < nSmiles; ++i)
            {
                atm[i]    = VOL_QUOTES[i][0];
                rr[i][0]  = VOL_QUOTES[i][1];
                rr[i][1]  = VOL_QUOTES[i][3];
                str[i][0] = VOL_QUOTES[i][2];
                str[i][1] = VOL_QUOTES[i][4];
            }
            InterpolatedStrikeSmileDeltaTermStructure term = InterpolatedStrikeSmileDeltaTermStructure.of(DoubleArray.copyOf(expiry), DoubleArray.of(0.1, 0.25), DoubleArray.copyOf(atm), DoubleMatrix.copyOf(rr), DoubleMatrix.copyOf(str), ACT_365F, LINEAR, FLAT, FLAT, PCHIP, FLAT, FLAT);

            EXP_VOLS = BlackFxOptionSmileVolatilities.of(VOL_NAME, GBP_USD, VALUATION_DATE.atTime(VALUATION_TIME).atZone(ZONE), term);
            for (int i = 0; i < nSmiles; ++i)
            {
                atm[i]    = VOL_QUOTES_1[i][0];
                rr[i][0]  = VOL_QUOTES_1[i][1];
                rr[i][1]  = VOL_QUOTES_1[i][3];
                str[i][0] = VOL_QUOTES_1[i][2];
                str[i][1] = VOL_QUOTES_1[i][4];
            }
            InterpolatedStrikeSmileDeltaTermStructure term1 = InterpolatedStrikeSmileDeltaTermStructure.of(DoubleArray.copyOf(expiry), DoubleArray.of(0.1, 0.25), DoubleArray.copyOf(atm), DoubleMatrix.copyOf(rr), DoubleMatrix.copyOf(str), ACT_365F, LINEAR, FLAT, FLAT, PCHIP, FLAT, FLAT);

            EXP_VOLS_1 = BlackFxOptionSmileVolatilities.of(VOL_NAME, GBP_USD, VALUATION_DATE_1.atTime(VALUATION_TIME_1).atZone(ZONE), term1);
            ImmutableList.Builder <FxOptionVolatilitiesNode> nodeBuilder  = ImmutableList.builder();
            ImmutableMap.Builder <QuoteId, double>           quoteBuilder = ImmutableMap.builder();
            for (int i = 0; i < SURFACE_TENORS.Count; ++i)
            {
                for (int j = 0; j < SURFACE_STRIKES.Count; ++j)
                {
                    QuoteId quoteId = QuoteId.of(StandardId.of("OG", GBP_USD.ToString() + "_" + SURFACE_TENORS[i].ToString() + "_" + SURFACE_STRIKES[j]));
                    quoteBuilder.put(quoteId, SURFACE_VOL_QUOTES[i][j]);
                    nodeBuilder.add(FxOptionVolatilitiesNode.of(GBP_USD, SPOT_OFFSET, BDA, ValueType.BLACK_VOLATILITY, quoteId, SURFACE_TENORS[i], SimpleStrike.of(SURFACE_STRIKES[j])));
                }
            }
            SURFACE_NODES  = nodeBuilder.build();
            SURFACE_QUOTES = quoteBuilder.build();
            IList <double> expiry = new List <double>();
            IList <double> strike = new List <double>();
            IList <double> vols   = new List <double>();

            for (int i = 0; i < SURFACE_TENORS.Count; ++i)
            {
                for (int j = 0; j < SURFACE_STRIKES.Count; ++j)
                {
                    double yearFraction = ACT_365F.relativeYearFraction(VALUATION_DATE, BDA.adjust(SPOT_OFFSET.adjust(VALUATION_DATE, REF_DATA).plus(SURFACE_TENORS[i]), REF_DATA));
                    expiry.Add(yearFraction);
                    strike.Add(SURFACE_STRIKES[j]);
                    vols.Add(SURFACE_VOL_QUOTES[i][j]);
                }
            }
            SurfaceInterpolator      interp  = GridSurfaceInterpolator.of(LINEAR, PCHIP);
            InterpolatedNodalSurface surface = InterpolatedNodalSurface.ofUnsorted(Surfaces.blackVolatilityByExpiryStrike(VOL_NAME.Name, ACT_365F), DoubleArray.copyOf(expiry), DoubleArray.copyOf(strike), DoubleArray.copyOf(vols), interp);

            SURFACE_EXP_VOLS = BlackFxOptionSurfaceVolatilities.of(VOL_NAME, GBP_USD, VALUATION_DATE.atTime(VALUATION_TIME).atZone(ZONE), surface);
        }