コード例 #1
0
        public override Lattice tree(TimeGrid grid)
        {
            TermStructureFittingParameter phi = new TermStructureFittingParameter(termStructure());

            ShortRateDynamics numericDynamics =
                new Dynamics(phi, a(), sigma());

            TrinomialTree trinomial =
                new TrinomialTree(numericDynamics.process(), grid);
            ShortRateTree numericTree =
                new ShortRateTree(trinomial, numericDynamics, grid);

            TermStructureFittingParameter.NumericalImpl impl =
                (TermStructureFittingParameter.NumericalImpl)phi.implementation();
            impl.reset();
            double value = 1.0;
            double vMin  = -50.0;
            double vMax  = 50.0;

            for (int i = 0; i < (grid.size() - 1); i++)
            {
                double discountBond = termStructure().link.discount(grid[i + 1]);
                double xMin         = trinomial.underlying(i, 0);
                double dx           = trinomial.dx(i);
                Helper finder       = new Helper(i, xMin, dx, discountBond, numericTree);
                Brent  s1d          = new Brent();
                s1d.setMaxEvaluations(1000);
                value = s1d.solve(finder, 1e-7, value, vMin, vMax);
                impl.setvalue(grid[i], value);
            }
            return(numericTree);
        }
コード例 #2
0
        /// <summary>
        /// Calculate the Option Adjusted Spread (OAS)
        /// <remarks>
        /// Calculates the spread that needs to be added to the the
        /// reference curve so that the theoretical model value
        /// matches the marketPrice.
        /// </remarks>
        /// </summary>
        /// <param name="cleanPrice"></param>
        /// <param name="engineTS"></param>
        /// <param name="dayCounter"></param>
        /// <param name="compounding"></param>
        /// <param name="frequency"></param>
        /// <param name="settlement"></param>
        /// <param name="accuracy"></param>
        /// <param name="maxIterations"></param>
        /// <param name="guess"></param>
        /// <returns></returns>
        public double OAS(double cleanPrice,
                          Handle <YieldTermStructure> engineTS,
                          DayCounter dayCounter,
                          Compounding compounding,
                          Frequency frequency,
                          Date settlement   = null,
                          double accuracy   = 1.0e-10,
                          int maxIterations = 100,
                          double guess      = 0.0)
        {
            if (settlement == null)
            {
                settlement = settlementDate();
            }

            double dirtyPrice = cleanPrice + accruedAmount(settlement);

            var       f   = new NpvSpreadHelper(this);
            OasHelper obj = new OasHelper(f, dirtyPrice);

            Brent solver = new Brent();

            solver.setMaxEvaluations(maxIterations);

            double step = 0.001;
            double oas  = solver.solve(obj, accuracy, guess, step);

            return(continuousToConv(oas,
                                    this,
                                    engineTS,
                                    dayCounter,
                                    compounding,
                                    frequency));
        }
コード例 #3
0
        private double strikeFromPrice(double price, Option.Type optionType, double referenceStrike)
        {
            double a, b, min, max, k;

            if (optionType == Option.Type.Call)
            {
                a   = swapRateValue_;
                min = referenceStrike;
                b   = max = k = Math.Min(smileSection_.maxStrike(), shiftedUpperBound_);
            }
            else
            {
                a   = min = k = Math.Max(smileSection_.minStrike(), shiftedLowerBound_);
                b   = swapRateValue_;
                max = referenceStrike;
            }

            PriceHelper h      = new PriceHelper(smileSection_, optionType, price);
            Brent       solver = new Brent();

            try
            {
                k = solver.solve(h, 1.0E-5, swapRateValue_, a, b);
            }
            catch (Exception)
            {
                // use default value set above
            }

            return(Math.Min(Math.Max(k, min), max));
        }
コード例 #4
0
        //! Black volatility implied by the model
        public double impliedVolatility(double targetValue,
                                        double accuracy, int maxEvaluations, double minVol, double maxVol)
        {
            ImpliedVolatilityHelper f = new ImpliedVolatilityHelper(this, targetValue);
            Brent solver = new Brent();

            solver.setMaxEvaluations(maxEvaluations);
            return(solver.solve(f, accuracy, volatility_.link.value(), minVol, maxVol));
        }
コード例 #5
0
        public double MonthlyYield()
        {
            Brent solver = new Brent();

            solver.setMaxEvaluations(100);
            List <CashFlow> cf = expectedCashflows();

            MonthlyYieldFinder objective = new MonthlyYieldFinder(notional(settlementDate()), cf, settlementDate());

            return(solver.solve(objective, 1.0e-10, 0.02, 0.0, 1.0) / 100);
        }
コード例 #6
0
        public static double calculate(Instrument instrument, IPricingEngine engine, SimpleQuote volQuote,
                                       double targetValue, double accuracy, int maxEvaluations, double minVol, double maxVol)
        {
            instrument.setupArguments(engine.getArguments());
            engine.getArguments().validate();

            PriceError f      = new PriceError(engine, volQuote, targetValue);
            Brent      solver = new Brent();

            solver.setMaxEvaluations(maxEvaluations);
            double guess  = (minVol + maxVol) / 2.0;
            double result = solver.solve(f, accuracy, guess, minVol, maxVol);

            return(result);
        }
コード例 #7
0
        private List <double> spreadsVolImplied()
        {
            Brent         solver = new Brent();
            List <double> result = new InitializedList <double>(nOptionExpiries_, 0.0);
            double        guess = 0.0001, minSpread = -0.1, maxSpread = 0.1;

            for (int j = 0; j < nOptionExpiries_; ++j)
            {
                ObjectiveFunction f = new ObjectiveFunction(stripper1_, caps_[j], atmCapFloorPrices_[j]);
                solver.setMaxEvaluations(maxEvaluations_);
                double root = solver.solve(f, accuracy_, guess, minSpread, maxSpread);
                result[j] = root;
            }
            return(result);
        }
コード例 #8
0
        protected override double blackVolImpl(double t, double strike)
        {
            HestonProcess process = hestonModel_.link.process();

            double df        = process.riskFreeRate().link.discount(t, true);
            double div       = process.dividendYield().link.discount(t, true);
            double spotPrice = process.s0().link.value();

            double fwd = spotPrice
                         * process.dividendYield().link.discount(t, true)
                         / process.riskFreeRate().link.discount(t, true);

            var payoff = new PlainVanillaPayoff(fwd > strike ? Option.Type.Put : Option.Type.Call, strike);

            double kappa = hestonModel_.link.kappa();
            double theta = hestonModel_.link.theta();
            double rho   = hestonModel_.link.rho();
            double sigma = hestonModel_.link.sigma();
            double v0    = hestonModel_.link.v0();

            AnalyticHestonEngine.ComplexLogFormula cpxLogFormula = AnalyticHestonEngine.ComplexLogFormula.Gatheral;

            AnalyticHestonEngine hestonEnginePtr = null;

            double?npv         = null;
            int    evaluations = 0;

            AnalyticHestonEngine.doCalculation(
                df, div, spotPrice, strike, t,
                kappa, theta, sigma, v0, rho,
                payoff, integration_, cpxLogFormula,
                hestonEnginePtr, ref npv, ref evaluations);

            if (npv <= 0.0)
            {
                return(Math.Sqrt(theta));
            }

            Brent solver = new Brent();

            solver.setMaxEvaluations(10000);
            double guess    = Math.Sqrt(theta);
            double accuracy = Const.QL_EPSILON;

            var f = new ImpliedVolHelper(payoff.optionType(), strike, fwd, t, df, npv.Value);

            return(solver.solve(f, accuracy, guess, 0.01));
        }
コード例 #9
0
        /// <summary>
        /// Returns the Black implied forward yield volatility
        /// <remarks>
        /// the forward yield volatility, see Hull, Fourth Edition,
        /// Chapter 20, pg 536). Relevant only to European put/call
        /// schedules
        /// </remarks>
        /// </summary>
        /// <param name="targetValue"></param>
        /// <param name="discountCurve"></param>
        /// <param name="accuracy"></param>
        /// <param name="maxEvaluations"></param>
        /// <param name="minVol"></param>
        /// <param name="maxVol"></param>
        /// <returns></returns>
        public double impliedVolatility(double targetValue,
                                        Handle <YieldTermStructure> discountCurve,
                                        double accuracy,
                                        int maxEvaluations,
                                        double minVol,
                                        double maxVol)
        {
            calculate();
            Utils.QL_REQUIRE(!isExpired(), () => "instrument expired");
            double guess = 0.5 * (minVol + maxVol);

            blackDiscountCurve_.linkTo(discountCurve, false);
            ImpliedVolHelper f      = new ImpliedVolHelper(this, targetValue);
            Brent            solver = new Brent();

            solver.setMaxEvaluations(maxEvaluations);
            return(solver.solve(f, accuracy, guess, minVol, maxVol));
        }
コード例 #10
0
        public double value(double x)
        {
            // first find the right side of the interval
            double upper       = guess_;
            int    evaluations = maxEvaluations_;

            while (nonCentralDist_.value(upper) < x && evaluations > 0)
            {
                upper *= 2.0;
                --evaluations;
            }

            // use a brent solver for the rest
            Brent solver = new Brent();

            solver.setMaxEvaluations(evaluations);
            return(solver.solve(new IncChiQuareFinder(x, nonCentralDist_.value),
                                accuracy_, 0.75 * upper, (evaluations == maxEvaluations_) ? 0.0 : 0.5 * upper,
                                upper));
        }
コード例 #11
0
ファイル: G2.cs プロジェクト: OpenDerivatives/QLCore
            public double value(double x)
            {
                CumulativeNormalDistribution phi = new CumulativeNormalDistribution();
                double temp = (x - mux_) / sigmax_;
                double txy  = Math.Sqrt(1.0 - rhoxy_ * rhoxy_);

                Vector lambda = new Vector(size_);
                int    i;

                for (i = 0; i < size_; i++)
                {
                    double tau = (i == 0 ? t_[0] - T_ : t_[i] - t_[i - 1]);
                    double c   = (i == size_ - 1 ? (1.0 + rate_ * tau) : rate_ * tau);
                    lambda[i] = c * A_[i] * Math.Exp(-Ba_[i] * x);
                }

                SolvingFunction function = new SolvingFunction(lambda, Bb_);
                Brent           s1d      = new Brent();

                s1d.setMaxEvaluations(1000);
                double yb = s1d.solve(function, 1e-6, 0.00, -100.0, 100.0);

                double h1 = (yb - muy_) / (sigmay_ * txy) -
                            rhoxy_ * (x - mux_) / (sigmax_ * txy);
                double value = phi.value(-w_ * h1);


                for (i = 0; i < size_; i++)
                {
                    double h2 = h1 +
                                Bb_[i] * sigmay_ *Math.Sqrt(1.0 - rhoxy_ *rhoxy_);

                    double kappa = -Bb_[i] *
                                   (muy_ - 0.5 * txy * txy * sigmay_ * sigmay_ * Bb_[i] +
                                    rhoxy_ * sigmay_ * (x - mux_) / sigmax_);
                    value -= lambda[i] * Math.Exp(kappa) * phi.value(-w_ * h2);
                }

                return(Math.Exp(-0.5 * temp * temp) * value /
                       (sigmax_ * Math.Sqrt(2.0 * QLCore.Const.M_PI)));
            }
コード例 #12
0
            //! Tree build-up + numerical fitting to term-structure
            public ShortRateTree(TrinomialTree tree, ShortRateDynamics dynamics, TermStructureFittingParameter.NumericalImpl theta,
                                 TimeGrid timeGrid)
                : base(timeGrid, tree.size(1))
            {
                tree_     = tree;
                dynamics_ = dynamics;
                theta.reset();
                double value = 1.0;
                double vMin  = -100.0;
                double vMax  = 100.0;

                for (int i = 0; i < (timeGrid.size() - 1); i++)
                {
                    double discountBond = theta.termStructure().link.discount(t_[i + 1]);
                    Helper finder       = new Helper(i, discountBond, theta, this);
                    Brent  s1d          = new Brent();
                    s1d.setMaxEvaluations(1000);
                    value = s1d.solve(finder, 1e-7, value, vMin, vMax);
                    theta.change(value);
                }
            }
コード例 #13
0
ファイル: CashFlows.cs プロジェクト: OpenDerivatives/QLCore
        //! implied Z-spread.
        public static double zSpread(Leg leg, double npv, YieldTermStructure discount, DayCounter dayCounter, Compounding compounding,
                                     Frequency frequency, bool includeSettlementDateFlows, Date settlementDate = null,
                                     Date npvDate = null, double accuracy = 1.0e-10, int maxIterations = 100, double guess = 0.0)
        {
            if (settlementDate == null)
            {
                settlementDate = Settings.Instance.evaluationDate();
            }

            if (npvDate == null)
            {
                npvDate = settlementDate;
            }

            Brent solver = new Brent();

            solver.setMaxEvaluations(maxIterations);
            ZSpreadFinder objFunction = new ZSpreadFinder(leg, discount, npv, dayCounter, compounding, frequency,
                                                          includeSettlementDateFlows, settlementDate, npvDate);
            double step = 0.01;

            return(solver.solve(objFunction, accuracy, guess, step));
        }
コード例 #14
0
        // alternative delta type
        private double strikeFromDelta(double delta, DeltaVolQuote.DeltaType dt)
        {
            double res = 0.0;
            double arg = 0.0;
            InverseCumulativeNormal f = new InverseCumulativeNormal();

            Utils.QL_REQUIRE(delta * phi_ >= 0.0, () => "Option type and delta are incoherent.");

            switch (dt)
            {
            case DeltaVolQuote.DeltaType.Spot:
                Utils.QL_REQUIRE(Math.Abs(delta) <= fDiscount_, () => "Spot delta out of range.");
                arg = -phi_ *f.value(phi_ *delta / fDiscount_) * stdDev_ + 0.5 * stdDev_ * stdDev_;

                res = forward_ * Math.Exp(arg);
                break;

            case DeltaVolQuote.DeltaType.Fwd:
                Utils.QL_REQUIRE(Math.Abs(delta) <= 1.0, () => "Forward delta out of range.");
                arg = -phi_ *f.value(phi_ *delta) * stdDev_ + 0.5 * stdDev_ * stdDev_;

                res = forward_ * Math.Exp(arg);
                break;

            case DeltaVolQuote.DeltaType.PaSpot:
            case DeltaVolQuote.DeltaType.PaFwd:
                // This has to be solved numerically. One of the
                // problems is that the premium adjusted call delta is
                // not monotonic in strike, such that two solutions
                // might occur. The one right to the max of the delta is
                // considered to be the correct strike.  Some proper
                // interval bounds for the strike need to be chosen, the
                // numerics can otherwise be very unreliable and
                // unstable.  I've chosen Brent over Newton, since the
                // interval can be specified explicitly and we can not
                // run into the area on the left of the maximum.  The
                // put delta doesn't have this property and can be
                // solved without any problems, but also numerically.

                BlackDeltaPremiumAdjustedSolverClass f1 = new BlackDeltaPremiumAdjustedSolverClass(
                    ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_, delta);

                Brent solver = new Brent();
                solver.setMaxEvaluations(1000);
                double accuracy = 1.0e-10;

                double rightLimit = 0.0;
                double leftLimit  = 0.0;

                // Strike of not premium adjusted is always to the right of premium adjusted
                if (dt == DeltaVolQuote.DeltaType.PaSpot)
                {
                    rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Spot);
                }
                else
                {
                    rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Fwd);
                }

                if (phi_ < 0)
                {
                    // if put
                    res = solver.solve(f1, accuracy, rightLimit, 0.0, spot_ * 100.0);
                    break;
                }
                else
                {
                    // find out the left limit which is the strike
                    // corresponding to the value where premium adjusted
                    // deltas have their maximum.

                    BlackDeltaPremiumAdjustedMaxStrikeClass g = new BlackDeltaPremiumAdjustedMaxStrikeClass(
                        ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_);

                    leftLimit = solver.solve(g, accuracy, rightLimit * 0.5, 0.0, rightLimit);

                    double guess = leftLimit + (rightLimit - leftLimit) * 0.5;

                    res = solver.solve(f1, accuracy, guess, leftLimit, rightLimit);
                } // end if phi<0 else

                break;


            default:
                Utils.QL_FAIL("invalid delta type");
                break;
            }

            return(res);
        }
コード例 #15
0
        public void calculate()
        {
            // we might have to call initialize even if the curve is initialized
            // and not moving, just because helpers might be date relative and change
            // with evaluation date change.
            // anyway it makes little sense to use date relative helpers with a
            // non-moving curve if the evaluation date changes
            if (!initialized_ || ts_.moving_)
            {
                initialize();
            }

            // setup helpers
            for (int j = firstAliveHelper_; j < n_; ++j)
            {
                BootstrapHelper <U> helper = ts_.instruments_[j];
                // check for valid quote
                Utils.QL_REQUIRE(helper.quote().link.isValid(), () =>
                                 (j + 1) + " instrument (maturity: " +
                                 helper.pillarDate() + ") has an invalid quote");
                // don't try this at home!
                // This call creates helpers, and removes "const".
                // There is a significant interaction with observability.
                ts_.setTermStructure(ts_.instruments_[j]);
            }

            List <double> times         = ts_.times_;
            List <double> data          = ts_.data_;
            double        accuracy      = accuracy_ != null ? accuracy_.Value : ts_.accuracy_;
            int           maxIterations = ts_.maxIterations() - 1;

            // there might be a valid curve state to use as guess
            bool validData = validCurve_;

            for (int iteration = 0; ; ++iteration)
            {
                previousData_ = new List <double>(ts_.data_);

                List <double?> minValues = new InitializedList <double?>(alive_ + 1, null);
                List <double?> maxValues = new InitializedList <double?>(alive_ + 1, null);
                List <int>     attempts  = new InitializedList <int>(alive_ + 1, 1);

                for (int i = 1; i <= alive_; ++i)
                {
                    // shorter aliases for readability and to avoid duplication
                    double?min = minValues[i];
                    double?max = maxValues[i];

                    // bracket root and calculate guess
                    if (min == null)
                    {
                        min = (minValue_ != null ? minValue_ :
                               ts_.minValueAfter(i, ts_, validData, firstAliveHelper_));
                        max = (maxValue_ != null ? maxValue_ :
                               ts_.maxValueAfter(i, ts_, validData, firstAliveHelper_));
                    }
                    else
                    {
                        min = (min.Value < 0.0 ? min.Value * minFactor_ : min.Value / minFactor_);
                        max = (max.Value > 0.0 ? max.Value * maxFactor_ : max.Value / maxFactor_);
                    }
                    double guess = ts_.guess(i, ts_, validData, firstAliveHelper_);

                    // adjust guess if needed
                    if (guess >= max.Value)
                    {
                        guess = max.Value - (max.Value - min.Value) / 5.0;
                    }
                    else if (guess <= min.Value)
                    {
                        guess = min.Value + (max.Value - min.Value) / 5.0;
                    }

                    // extend interpolation if needed
                    if (!validData)
                    {
                        try
                        {
                            // extend interpolation a point at a time
                            // including the pillar to be boostrapped
                            ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, i + 1, ts_.data_);
                        }
                        catch (Exception)
                        {
                            if (!ts_.interpolator_.global)
                            {
                                throw; // no chance to fix it in a later iteration
                            }
                            // otherwise use Linear while the target
                            // interpolation is not usable yet
                            ts_.interpolation_ = new Linear().interpolate(ts_.times_, i + 1, ts_.data_);
                        }
                        ts_.interpolation_.update();
                    }

                    try
                    {
                        var error = new BootstrapError <T, U>(ts_, ts_.instruments_[i - 1], i);
                        if (validData)
                        {
                            ts_.data_[i] = solver_.solve(error, accuracy, guess, min.Value, max.Value);
                        }
                        else
                        {
                            ts_.data_[i] = firstSolver_.solve(error, accuracy, guess, min.Value, max.Value);
                        }
                    }
                    catch (Exception e)
                    {
                        if (validCurve_)
                        {
                            // the previous curve state might have been a
                            // bad guess, so we retry without using it.
                            // This would be tricky to do here (we're
                            // inside multiple nested for loops, we need
                            // to re-initialize...), so we invalidate the
                            // curve, make a recursive call and then exit.
                            validCurve_ = initialized_ = false;
                            calculate();
                            return;
                        }

                        // If we have more attempts left on this iteration, try again. Note that the max and min
                        // bounds will be widened on the retry.
                        if (attempts[i] < maxAttempts_)
                        {
                            attempts[i]++;
                            i--;
                            continue;
                        }

                        if (dontThrow_)
                        {
                            // Use the fallback value
                            var error = new BootstrapError <T, U>(ts_, ts_.instruments_[i - 1], i);
                            ts_.data_[i] = dontThrowFallback(error, min.Value, max.Value, dontThrowSteps_);

                            // Remember to update the interpolation. If we don't and we are on the last "i", we will still
                            // have the last attempted value in the solver being used in ts_->interpolation_.
                            ts_.interpolation_.update();
                        }
                        else
                        {
                            Utils.QL_FAIL((iteration + 1) + " iteration: failed " +
                                          "at " + (i) + " alive instrument, " +
                                          "pillar " + ts_.instruments_[i - 1].pillarDate() + ", " +
                                          "maturity " + ts_.instruments_[i - 1].maturityDate() +
                                          ", reference date " + ts_.dates_[0] +
                                          ": " + e.Message);
                        }
                    }
                }

                if (!loopRequired_)
                {
                    break; // no need for convergence loop
                }
                // exit condition
                double change = Math.Abs(data[1] - previousData_[1]);
                for (int i = 2; i <= alive_; ++i)
                {
                    change = Math.Max(change, Math.Abs(data[i] - previousData_[i]));
                }
                if (change <= accuracy) // convergence reached
                {
                    break;
                }

                Utils.QL_REQUIRE(iteration < maxIterations, () =>
                                 "convergence not reached after " + iteration +
                                 " iterations; last improvement " + change +
                                 ", required accuracy " + accuracy);
                validData = true;
            }
            validCurve_ = true;
        }
コード例 #16
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.settlementMethod != Settlement.Method.ParYieldCurve, () =>
                             "cash-settled (ParYieldCurve) swaptions not priced by Jamshidian engine");

            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () =>
                             "cannot use the Jamshidian decomposition on exotic swaptions");

            Utils.QL_REQUIRE(arguments_.swap.spread.IsEqual(0.0), () =>
                             "non zero spread (" + arguments_.swap.spread + ") not allowed");

            Date       referenceDate;
            DayCounter dayCounter;

            ITermStructureConsistentModel tsmodel = (ITermStructureConsistentModel)base.model_.link;

            try
            {
                if (tsmodel != null)
                {
                    referenceDate = tsmodel.termStructure().link.referenceDate();
                    dayCounter    = tsmodel.termStructure().link.dayCounter();
                }
                else
                {
                    referenceDate = termStructure_.link.referenceDate();
                    dayCounter    = termStructure_.link.dayCounter();
                }
            }
            catch
            {
                referenceDate = termStructure_.link.referenceDate();
                dayCounter    = termStructure_.link.dayCounter();
            }

            List <double> amounts = new InitializedList <double>(arguments_.fixedCoupons.Count);

            for (int i = 0; i < amounts.Count; i++)
            {
                amounts[i] = arguments_.fixedCoupons[i];
            }
            amounts[amounts.Count - 1] = amounts.Last() + arguments_.nominal;

            double maturity = dayCounter.yearFraction(referenceDate,
                                                      arguments_.exercise.date(0));

            List <double> fixedPayTimes = new InitializedList <double>(arguments_.fixedPayDates.Count);

            for (int i = 0; i < fixedPayTimes.Count; i++)
            {
                fixedPayTimes[i] =
                    dayCounter.yearFraction(referenceDate,
                                            arguments_.fixedPayDates[i]);
            }

            rStarFinder finder = new rStarFinder(model_, arguments_.nominal, maturity,
                                                 fixedPayTimes, amounts);
            Brent  s1d       = new Brent();
            double minStrike = -10.0;
            double maxStrike = 10.0;

            s1d.setMaxEvaluations(10000);
            s1d.setLowerBound(minStrike);
            s1d.setUpperBound(maxStrike);
            double rStar = s1d.solve(finder, 1e-8, 0.05, minStrike, maxStrike);

            Option.Type w = arguments_.type == VanillaSwap.Type.Payer ?
                            Option.Type.Put : Option.Type.Call;
            int size = arguments_.fixedCoupons.Count;

            double value = 0.0;

            for (int i = 0; i < size; i++)
            {
                double fixedPayTime =
                    dayCounter.yearFraction(referenceDate,
                                            arguments_.fixedPayDates[i]);
                double strike = model_.link.discountBond(maturity,
                                                         fixedPayTime,
                                                         rStar);
                double dboValue = model_.link.discountBondOption(
                    w, strike, maturity,
                    fixedPayTime);
                value += amounts[i] * dboValue;
            }
            results_.value = value;
        }