예제 #1
0
        private void initialize()
        {
            Utils.QL_REQUIRE(dates_.Count >= interpolator_.requiredPoints,
                             () => "not enough input dates givesn");
            Utils.QL_REQUIRE(this.data_.Count == this.dates_.Count,
                             () => "dates/data count mismatch");
            Utils.QL_REQUIRE(this.data_[0] == 1.0, () => "the first discount must be == 1.0 " +
                             "to flag the corrsponding date as settlement date");

            times_ = new InitializedList <double>(dates_.Count - 1);
            times_.Add(0.0);
            for (int i = 1; i < dates_.Count; i++)
            {
                Utils.QL_REQUIRE(dates_[i] > dates_[i - 1],
                                 () => "invalid date (" + dates_[i] + ", vs " + dates_[i - 1] + ")");
                times_[i] = dayCounter().yearFraction(dates_[0], dates_[i]);
                Utils.QL_REQUIRE(!Utils.close(this.times_[i], this.times_[i - 1]),
                                 () => "two dates correspond to the same time " +
                                 "under this curve's day count convention");
                Utils.QL_REQUIRE(this.data_[i] > 0.0, () => "negative discount");

#if !QL_NEGATIVE_RATES
                Utils.QL_REQUIRE(this.data_[i] <= this.data_[i - 1],
                                 () => "negative forward rate implied by the discount " +
                                 this.data_[i] + " at " + dates_[i] +
                                 " (t=" + this.times_[i] + ") after the discount " +
                                 this.data_[i - 1] + " at " + dates_[i - 1] +
                                 " (t=" + this.times_[i - 1] + ")");
#endif
            }

            setupInterpolation();
            interpolation_.update();
        }
예제 #2
0
        //public InterpolatedDiscountCurve(List<Date> dates, List<double> discounts, DayCounter dayCounter,
        //                                 Calendar cal = Calendar(), Interpolator interpolator = Interpolator())
        public InterpolatedDiscountCurve(List <Date> dates, List <double> discounts, DayCounter dayCounter,
                                         Calendar cal, List <Handle <Quote> > jumps = null, List <Date> jumpDates = null,
                                         Interpolator interpolator = default(Interpolator))
            : base(dates.First(), cal, dayCounter, jumps, jumpDates)
        {
            times_        = new List <double>();
            data_         = discounts;
            interpolator_ = interpolator;
            dates_        = dates;

            if (dates_.empty())
            {
                throw new ApplicationException("no input dates given");
            }
            if (data_.empty())
            {
                throw new ApplicationException("no input discount factors given");
            }
            if (data_.Count != dates_.Count)
            {
                throw new ApplicationException("dates/discount factors count mismatch");
            }
            if (data_[0] != 1.0)
            {
                throw new ApplicationException("the first discount must be == 1.0 " +
                                               "to flag the corrsponding date as settlement date");
            }

            times_ = new InitializedList <double>(dates_.Count - 1);
            times_.Add(0.0);
            for (int i = 1; i < dates_.Count; i++)
            {
                if (!(dates_[i] > dates_[i - 1]))
                {
                    throw new ApplicationException("invalid date (" + dates_[i] + ", vs " + dates_[i - 1] + ")");
                }
                if (!(data_[i] > 0.0))
                {
                    throw new ApplicationException("negative discount");
                }
                times_[i] = dayCounter.yearFraction(dates_[0], dates_[i]);
                if (Utils.close(times_[i], times_[i - 1]))
                {
                    throw new ApplicationException("two dates correspond to the same time " +
                                                   "under this curve's day count convention");
                }
            }

            setupInterpolation();
            interpolation_.update();
        }
예제 #3
0
        /// Spline  ///
        public void splincalculation()
        {
            double rightConditionValue = 0.0;
            double leftConditionValue  = 0.0;
            int    size = strikes_.Count + 2;

            List <List <double> > bspriceSpline = new InitializedList <List <double> >();


            gamma_ = new InitializedList <Vector>();
            g_     = new InitializedList <Vector>();

            for (int i = 0; i < fwMoneynessGrid_.rows(); i++)
            {
                leftConditionValue = spot_ * dividendTS_.link.discount(times_[i], true) / riskFreeTS_.link.discount(times_[i], true);
                bspriceSpline.Add(new InitializedList <double>());
                strikesSpline_.Add(new InitializedList <double>());

                bspriceSpline[i].Add(leftConditionValue);
                strikesSpline_[i].Add(0.0);
                for (int j = 0; j < fwMoneynessGrid_.columns(); j++)
                {
                    bspriceSpline[i].Add(X_[i, j]);
                    strikesSpline_[i].Add(strikes_[j]);
                }

                rightConditionValue = 0.0;
                bspriceSpline[i].Add(rightConditionValue);
                strikesSpline_[i].Add(spot_ * 10000);
                g_i_.Add(new CubicInterpolation(strikesSpline_[i],
                                                size,
                                                bspriceSpline[i],
                                                CubicInterpolation.DerivativeApprox.Spline,
                                                true,
                                                CubicInterpolation.BoundaryCondition.SecondDerivative,
                                                leftConditionValue,
                                                CubicInterpolation.BoundaryCondition.SecondDerivative,
                                                rightConditionValue));

                List <double> tempList = new List <double>();
                tempList    = g_i_[i].bCoefficients();
                tempList[0] = 0.0;
                tempList[tempList.Count - 1] = 0.0;
                gamma_.Add(new Vector(tempList));
                g_.Add(new Vector(strikes_));
            }
        }
예제 #4
0
        // McSimulation implementation
        protected override TimeGrid timeGrid()
        {
            Date          referenceDate = process_.riskFreeRate().link.referenceDate();
            DayCounter    voldc         = process_.blackVolatility().link.dayCounter();
            List <double> fixingTimes   = new  InitializedList <double>(arguments_.fixingDates.Count);

            for (int i = 0; i < arguments_.fixingDates.Count; i++)
            {
                if (arguments_.fixingDates[i] >= referenceDate)
                {
                    double t = voldc.yearFraction(referenceDate,
                                                  arguments_.fixingDates[i]);
                    fixingTimes.Add(t);
                }
            }
            // handle here maxStepsPerYear
            return(new TimeGrid(fixingTimes.Last(), fixingTimes.Count));
        }
예제 #5
0
        public Concentrating1dMesher(double start, double end, int size,
                                     List <Tuple <double?, double?, bool> > cPoints,
                                     double tol = 1e-8)
            : base(size)
        {
            Utils.QL_REQUIRE(end > start, () => "end must be larger than start");

            List <double?> points = new List <double?>(), betas = new List <double?>();

            foreach (Tuple <double?, double?, bool> iter in cPoints)
            {
                points.Add(iter.Item1);
                betas.Add((iter.Item2 * (end - start)) * (iter.Item2 * (end - start)));
            }

            // get scaling factor a so that y(1) = end
            double aInit = 0.0;

            for (int i = 0; i < points.Count; ++i)
            {
                double c1 = Utils.Asinh((start - points[i].GetValueOrDefault()) / betas[i].GetValueOrDefault());
                double c2 = Utils.Asinh((end - points[i].GetValueOrDefault()) / betas[i].GetValueOrDefault());
                aInit += (c2 - c1) / points.Count;
            }

            OdeIntegrationFct fct = new OdeIntegrationFct(points, betas, tol);
            double            a   = new Brent().solve(
                new OdeSolver(fct, start, 0.0, 1.0, end),
                tol, aInit, 0.1 * aInit);

            // solve ODE for all grid points
            Vector x = new Vector(size), y = new Vector(size);

            x[0] = 0.0;
            y[0] = start;
            double dx = 1.0 / (size - 1);

            for (int i = 1; i < size; ++i)
            {
                x[i] = i * dx;
                y[i] = fct.solve(a, y[i - 1], x[i - 1], x[i]);
            }

            // eliminate numerical noise and ensure y(1) = end
            double dy = y[y.Count - 1] - end;

            for (int i = 1; i < size; ++i)
            {
                y[i] -= i * dx * dy;
            }

            LinearInterpolation odeSolution = new LinearInterpolation(x, x.Count, y);

            // ensure required points are part of the grid
            List <Pair <double?, double?> > w =
                new InitializedList <Pair <double?, double?> >(1, new Pair <double?, double?>(0.0, 0.0));

            for (int i = 0; i < points.Count; ++i)
            {
                if (cPoints[i].Item3 && points[i] > start && points[i] < end)
                {
                    int j = y.distance(y[0], y.BinarySearch(points[i].Value));

                    double e = new Brent().solve(
                        new OdeSolver2(odeSolution.value, points[i].Value),
                        Const.QL_EPSILON, x[j], 0.5 / size);

                    w.Add(new Pair <double?, double?>(Math.Min(x[size - 2], x[j]), e));
                }
            }
            w.Add(new Pair <double?, double?>(1.0, 1.0));
            w = w.OrderBy(xx => xx.first).Distinct(new equal_on_first()).ToList();

            List <double> u = new List <double>(w.Count), z = new List <double>(w.Count);

            for (int i = 0; i < w.Count; ++i)
            {
                u[i] = w[i].first.GetValueOrDefault();
                z[i] = w[i].second.GetValueOrDefault();
            }
            LinearInterpolation transform = new LinearInterpolation(u, u.Count, z);

            for (int i = 0; i < size; ++i)
            {
                locations_[i] = odeSolution.value(transform.value(i * dx));
            }

            for (int i = 0; i < size - 1; ++i)
            {
                dplus_[i] = dminus_[i + 1] = locations_[i + 1] - locations_[i];
            }
            dplus_[dplus_.Count] = null;
            dminus_[0]           = null;
        }
예제 #6
0
        protected Cube sabrCalibration(Cube marketVolCube)
        {
            List <double> optionTimes = marketVolCube.optionTimes();
            List <double> swapLengths = marketVolCube.swapLengths();
            List <Date>   optionDates = marketVolCube.optionDates();
            List <Period> swapTenors  = marketVolCube.swapTenors();
            Matrix        alphas      = new Matrix(optionTimes.Count, swapLengths.Count, 0.0);
            Matrix        betas       = new Matrix(alphas);
            Matrix        nus         = new Matrix(alphas);
            Matrix        rhos        = new Matrix(alphas);
            Matrix        forwards    = new Matrix(alphas);
            Matrix        errors      = new Matrix(alphas);
            Matrix        maxErrors   = new Matrix(alphas);
            Matrix        endCriteria = new Matrix(alphas);

            List <Matrix> tmpMarketVolCube = marketVolCube.points();

            List <double> strikes      = new InitializedList <double>(strikeSpreads_.Count);
            List <double> volatilities = new InitializedList <double>(strikeSpreads_.Count);

            for (int j = 0; j < optionTimes.Count; j++)
            {
                for (int k = 0; k < swapLengths.Count; k++)
                {
                    double atmForward = atmStrike(optionDates[j], swapTenors[k]);
                    double shiftTmp   = atmVol_.link.shift(optionTimes[j], swapLengths[k]);
                    strikes.Clear();
                    volatilities.Clear();
                    for (int i = 0; i < nStrikes_; i++)
                    {
                        double strike = atmForward + strikeSpreads_[i];
                        if (strike + shiftTmp >= cutoffStrike_)
                        {
                            strikes.Add(strike);
                            Matrix matrix = tmpMarketVolCube[i];
                            volatilities.Add(matrix[j, k]);
                        }
                    }

                    List <double> guess = parametersGuess_.value(optionTimes[j], swapLengths[k]);


                    SABRInterpolation sabrInterpolation = new SABRInterpolation(strikes, strikes.Count,
                                                                                volatilities,
                                                                                optionTimes[j], atmForward,
                                                                                guess[0], guess[1],
                                                                                guess[2], guess[3],
                                                                                isParameterFixed_[0],
                                                                                isParameterFixed_[1],
                                                                                isParameterFixed_[2],
                                                                                isParameterFixed_[3],
                                                                                vegaWeightedSmileFit_,
                                                                                endCriteria_,
                                                                                optMethod_,
                                                                                errorAccept_,
                                                                                useMaxError_,
                                                                                maxGuesses_
                                                                                );// shiftTmp
                    sabrInterpolation.update();

                    double rmsError = sabrInterpolation.rmsError();
                    double maxError = sabrInterpolation.maxError();
                    alphas     [j, k] = sabrInterpolation.alpha();
                    betas      [j, k] = sabrInterpolation.beta();
                    nus        [j, k] = sabrInterpolation.nu();
                    rhos       [j, k] = sabrInterpolation.rho();
                    forwards   [j, k] = atmForward;
                    errors     [j, k] = rmsError;
                    maxErrors  [j, k] = maxError;
                    endCriteria[j, k] = (double)sabrInterpolation.endCriteria();

                    Utils.QL_REQUIRE(endCriteria[j, k].IsNotEqual((double)EndCriteria.Type.MaxIterations), () =>
                                     "global swaptions calibration failed: " +
                                     "MaxIterations reached: " + "\n" +
                                     "option maturity = " + optionDates[j] + ", \n" +
                                     "swap tenor = " + swapTenors[k] + ", \n" +
                                     "error = " + (errors[j, k]) + ", \n" +
                                     "max error = " + (maxErrors[j, k]) + ", \n" +
                                     "   alpha = " + alphas[j, k] + "n" +
                                     "   beta = " + betas[j, k] + "\n" +
                                     "   nu = " + nus[j, k] + "\n" +
                                     "   rho = " + rhos[j, k] + "\n"
                                     );

                    Utils.QL_REQUIRE(useMaxError_ ? maxError > 0 : rmsError < maxErrorTolerance_, () =>
                                     "global swaptions calibration failed: " +
                                     "option tenor " + optionDates[j] +
                                     ", swap tenor " + swapTenors[k] +
                                     (useMaxError_ ? ": max error " : ": error") +
                                     (useMaxError_ ? maxError : rmsError) +
                                     "   alpha = " + alphas[j, k] + "\n" +
                                     "   beta = " + betas[j, k] + "\n" +
                                     "   nu = " + nus[j, k] + "\n" +
                                     "   rho = " + rhos[j, k] + "\n" +
                                     (useMaxError_ ? ": error" : ": max error ") +
                                     (useMaxError_ ? rmsError :maxError)

                                     );
                }
            }
            Cube sabrParametersCube = new Cube(optionDates, swapTenors, optionTimes, swapLengths, 8, true, backwardFlat_);

            sabrParametersCube.setLayer(0, alphas);
            sabrParametersCube.setLayer(1, betas);
            sabrParametersCube.setLayer(2, nus);
            sabrParametersCube.setLayer(3, rhos);
            sabrParametersCube.setLayer(4, forwards);
            sabrParametersCube.setLayer(5, errors);
            sabrParametersCube.setLayer(6, maxErrors);
            sabrParametersCube.setLayer(7, endCriteria);

            return(sabrParametersCube);
        }
        public override void calculate()
        {
            /* this engine cannot really check for the averageType==Geometric
             * since it can be used as control variate for the Arithmetic version
             *  QL_REQUIRE(arguments_.averageType == Average::Geometric,
             *             "not a geometric average option");
             */

            if (!(arguments_.exercise.type() == Exercise.Type.European))
            {
                throw new ApplicationException("not an European Option");
            }

            double runningLog;
            int    pastFixings;

            if (arguments_.averageType == Average.Type.Geometric)
            {
                if (!(arguments_.runningAccumulator > 0.0))
                {
                    throw new ApplicationException("positive running product required: "
                                                   + arguments_.runningAccumulator + " not allowed");
                }
                runningLog =
                    Math.Log(arguments_.runningAccumulator.GetValueOrDefault());
                pastFixings = arguments_.pastFixings.GetValueOrDefault();
            }
            else      // it is being used as control variate
            {
                runningLog  = 1.0;
                pastFixings = 0;
            }

            PlainVanillaPayoff payoff = (PlainVanillaPayoff)(arguments_.payoff);

            if (payoff == null)
            {
                throw new ApplicationException("non-plain payoff given");
            }

            Date          referenceDate = process_.riskFreeRate().link.referenceDate();
            DayCounter    rfdc          = process_.riskFreeRate().link.dayCounter();
            DayCounter    divdc         = process_.dividendYield().link.dayCounter();
            DayCounter    voldc         = process_.blackVolatility().link.dayCounter();
            List <double> fixingTimes   = new InitializedList <double>(arguments_.fixingDates.Count());
            int           i;

            for (i = 0; i < arguments_.fixingDates.Count(); i++)
            {
                if (arguments_.fixingDates[i] >= referenceDate)
                {
                    double t = voldc.yearFraction(referenceDate,
                                                  arguments_.fixingDates[i]);
                    fixingTimes.Add(t);
                }
            }

            int    remainingFixings = fixingTimes.Count();
            int    numberOfFixings  = pastFixings + remainingFixings;
            double N = numberOfFixings;

            double pastWeight   = pastFixings / N;
            double futureWeight = 1.0 - pastWeight;

            /*double timeSum = std::accumulate(fixingTimes.begin(),
             *                             fixingTimes.end(), 0.0);*/
            double timeSum = 0;

            fixingTimes.ForEach((ii, vv) => timeSum += fixingTimes[ii]);

            double vola = process_.blackVolatility().link.blackVol(
                arguments_.exercise.lastDate(),
                payoff.strike());
            double temp = 0.0;

            for (i = pastFixings + 1; i < numberOfFixings; i++)
            {
                temp += fixingTimes[i - pastFixings - 1] * (N - i);
            }
            double variance   = vola * vola / N / N * (timeSum + 2.0 * temp);
            double dsigG_dsig = Math.Sqrt((timeSum + 2.0 * temp)) / N;
            double sigG       = vola * dsigG_dsig;
            double dmuG_dsig  = -(vola * timeSum) / N;

            Date   exDate       = arguments_.exercise.lastDate();
            double dividendRate = process_.dividendYield().link.
                                  zeroRate(exDate, divdc, Compounding.Continuous, Frequency.NoFrequency).rate();
            double riskFreeRate = process_.riskFreeRate().link.
                                  zeroRate(exDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate();
            double nu = riskFreeRate - dividendRate - 0.5 * vola * vola;

            double s = process_.stateVariable().link.value();

            if (!(s > 0.0))
            {
                throw new ApplicationException("positive underlying value required");
            }

            int    M   = (pastFixings == 0 ? 1 : pastFixings);
            double muG = pastWeight * runningLog / M +
                         futureWeight * Math.Log(s) + nu * timeSum / N;
            double forwardPrice = Math.Exp(muG + variance / 2.0);

            double riskFreeDiscount = process_.riskFreeRate().link.discount(
                arguments_.exercise.lastDate());

            BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance),
                                                        riskFreeDiscount);

            results_.value = black.value();
            results_.delta = futureWeight * black.delta(forwardPrice) * forwardPrice / s;
            results_.gamma = forwardPrice * futureWeight / (s * s)
                             * (black.gamma(forwardPrice) * futureWeight * forwardPrice
                                - pastWeight * black.delta(forwardPrice));

            double Nx_1, nx_1;
            CumulativeNormalDistribution CND = new CumulativeNormalDistribution();
            NormalDistribution           ND  = new NormalDistribution();

            if (sigG > Const.QL_Epsilon)
            {
                double x_1 = (muG - Math.Log(payoff.strike()) + variance) / sigG;
                Nx_1 = CND.value(x_1);
                nx_1 = ND.value(x_1);
            }
            else
            {
                Nx_1 = (muG > Math.Log(payoff.strike()) ? 1.0 : 0.0);
                nx_1 = 0.0;
            }
            results_.vega = forwardPrice * riskFreeDiscount *
                            ((dmuG_dsig + sigG * dsigG_dsig) * Nx_1 + nx_1 * dsigG_dsig);

            if (payoff.optionType() == Option.Type.Put)
            {
                results_.vega -= riskFreeDiscount * forwardPrice *
                                 (dmuG_dsig + sigG * dsigG_dsig);
            }

            double tRho = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(),
                                            arguments_.exercise.lastDate());

            results_.rho = black.rho(tRho) * timeSum / (N * tRho)
                           - (tRho - timeSum / N) * results_.value;

            double tDiv = divdc.yearFraction(
                process_.dividendYield().link.referenceDate(),
                arguments_.exercise.lastDate());

            results_.dividendRho = black.dividendRho(tDiv) * timeSum / (N * tDiv);

            results_.strikeSensitivity = black.strikeSensitivity();

            results_.theta = Utils.blackScholesTheta(process_,
                                                     results_.value.GetValueOrDefault(),
                                                     results_.delta.GetValueOrDefault(),
                                                     results_.gamma.GetValueOrDefault());
        }
예제 #8
0
파일: GMRES.cs 프로젝트: igitur/qlnet
        protected GMRESResult solveImpl(Vector b, Vector x0)
        {
            double      bn = Vector.Norm2(b);
            GMRESResult result;

            if (bn.IsEqual(0.0))
            {
                result = new GMRESResult(new InitializedList <double>(1, 0.0), b);
                return(result);
            }

            Vector x = !x0.empty() ? x0 : new Vector(b.size(), 0.0);
            Vector r = b - A_(x);

            double g = Vector.Norm2(r);

            if (g / bn < relTol_)
            {
                result = new GMRESResult(new InitializedList <double>(1, g / bn), x);
                return(result);
            }

            List <Vector> v = new InitializedList <Vector>(1, r / g);
            List <Vector> h = new InitializedList <Vector>(1, new Vector(maxIter_, 0.0));
            List <double> c = new List <double>(maxIter_ + 1),
                          s = new List <double>(maxIter_ + 1),
                          z = new List <double>(maxIter_ + 1);

            z[0] = g;

            List <double> errors = new InitializedList <double>(1, g / bn);

            for (int j = 0; j < maxIter_ && errors.Last() >= relTol_; ++j)
            {
                h.Add(new Vector(maxIter_, 0.0));
                Vector w = A_((M_ != null) ? M_(v[j]) : v[j]);

                for (int i = 0; i <= j; ++i)
                {
                    h[i][j] = Vector.DotProduct(w, v[i]);
                    w      -= h[i][j] * v[i];
                }

                h[j + 1][j] = Vector.Norm2(w);

                if (h[j + 1][j] < Const.QL_EPSILON * Const.QL_EPSILON)
                {
                    break;
                }

                v.Add(w / h[j + 1][j]);

                for (int i = 0; i < j; ++i)
                {
                    double h0 = c[i] * h[i][j] + s[i] * h[i + 1][j];
                    double h1 = -s[i] * h[i][j] + c[i] * h[i + 1][j];

                    h[i][j]     = h0;
                    h[i + 1][j] = h1;
                }

                double nu = Math.Sqrt((h[j][j]) * (h[j][j])
                                      + (h[j + 1][j]) * (h[j + 1][j]));

                c[j] = h[j][j] / nu;
                s[j] = h[j + 1][j] / nu;

                h[j][j]     = nu;
                h[j + 1][j] = 0.0;

                z[j + 1] = -s[j] * z[j];
                z[j]     = c[j] * z[j];

                errors.Add(Math.Abs(z[j + 1] / bn));
            }

            int k = v.Count - 1;

            Vector y = new Vector(k, 0.0);

            y[k - 1] = z[k - 1] / h[k - 1][k - 1];

            for (int i = k - 2; i >= 0; --i)
            {
                y[i] = (z[i] - h[i].inner_product(
                            i + 1, k, i + 1, y, 0.0)) / h[i][i];
            }

            Vector xm = new Vector(x.Count, 0.0);

            for (int i = 0; i < x.Count; i++)
            {
                xm[i] = v[i].inner_product(0, k, 0, y, 0.0);
            }

            xm = x + ((M_ != null) ? M_(xm) : xm);

            result = new GMRESResult(errors, xm);
            return(result);
        }