コード例 #1
0
        private static Matrix <double> CalcFactorCovarianceSquareRoots(MultiFactorParameters <T> modelParameters, double timeIncrement)

        {
            int numFactors = modelParameters.NumFactors;
            // TODO does Math.NET have a more efficient representation of symmetric and triangular matrices?
            Matrix <double> covarianceMatrix = Matrix <double> .Build.Dense(numFactors, numFactors);

            for (int i = 0; i < numFactors; i++)
            {
                for (int j = i; j < numFactors; j++)
                {
                    double meanReversionsSum = modelParameters.Factors[i].MeanReversion +
                                               modelParameters.Factors[j].MeanReversion;

                    double covariance = modelParameters.FactorCorrelations[i, j] *
                                        CalcFactorContExt(meanReversionsSum, timeIncrement);

                    covarianceMatrix[i, j] = covariance;
                    if (i != j)
                    {
                        covarianceMatrix[j, i] = covariance;
                    }
                }
            }

            return(covarianceMatrix.Cholesky().Factor);
        }
コード例 #2
0
        private static double CalcDriftAdjustment(MultiFactorParameters <T> modelParameters, double timeToMaturity, T period)
        {
            double sum = 0.0;

            // TODO use symmetry to speed up?
            // TODO formulate as matrix multiplication as quadratic form?
            for (int i = 0; i < modelParameters.NumFactors; i++)
            {
                Factor <T> factor1 = modelParameters.Factors[i];
                if (!factor1.Volatility.TryGetValue(period, out double vol1))
                {
                    throw new ArgumentException($"Factor {i} of multi-factor model parameters does not contain vol for period {period}.",
                                                nameof(modelParameters));
                }
                double meanReversion1 = factor1.MeanReversion;
                for (int j = 0; j < modelParameters.NumFactors; j++)
                {
                    Factor <T> factor2 = modelParameters.Factors[j];
                    if (!factor2.Volatility.TryGetValue(period, out double vol2))
                    {
                        throw new ArgumentException($"Factor {j} of multi-factor model parameters does not contain vol for period {period}.",
                                                    nameof(modelParameters));
                    }
                    double meanReversion2 = factor2.MeanReversion;

                    sum += vol1 * vol2 * modelParameters.FactorCorrelations[i, j] *
                           CalcFactorContExt(meanReversion1 + meanReversion2, timeToMaturity);
                }
            }

            return(-sum / 2.0);
        }
コード例 #3
0
        public MultiFactorSpotPriceSimulator([NotNull] MultiFactorParameters <T> modelParameters, DateTime currentDateTime,
                                             [NotNull] IReadOnlyDictionary <T, double> forwardCurve, [NotNull] IEnumerable <T> simulatedPeriods,
                                             Func <DateTime, DateTime, double> timeFunc, [NotNull] IStandardNormalGenerator standardNormalGenerator) // TODO pass in random number generator factory
        {
            if (modelParameters == null)
            {
                throw new ArgumentNullException(nameof(modelParameters));
            }
            if (forwardCurve == null)
            {
                throw new ArgumentNullException(nameof(forwardCurve));
            }
            if (simulatedPeriods == null)
            {
                throw new ArgumentNullException(nameof(simulatedPeriods));
            }
            _standardNormalGenerator = standardNormalGenerator ?? throw new ArgumentNullException(nameof(standardNormalGenerator));

            T[] simulatedPeriodsArray = simulatedPeriods.ToArray();

            int numPeriods = simulatedPeriodsArray.Length;
            int numFactors = modelParameters.NumFactors;

            if (numPeriods == 0)
            {
                throw new ArgumentException(nameof(simulatedPeriods) + " argument cannot be empty.", nameof(simulatedPeriods));
            }

            int numRandomDimensions = numPeriods * numFactors;

            if (!_standardNormalGenerator.MatchesDimensions(numRandomDimensions))
            {
                throw new ArgumentException($"Injected normal random generator is not set up to generate with {numRandomDimensions} dimensions.", nameof(standardNormalGenerator));
            }

            _forwardPrices               = new double[numPeriods];
            _driftAdjustments            = new double[numPeriods];
            _reversionMultipliers        = new double[numPeriods, numFactors];
            _spotVols                    = new double[numPeriods, numFactors];
            _factorCovarianceSquareRoots = new Matrix <double> [numPeriods];
            _simulatedPeriods            = simulatedPeriodsArray;

            double timeToMaturityPrevious = 0;

            for (int i = 0; i < simulatedPeriodsArray.Length; i++)
            {
                T period = simulatedPeriodsArray[i];
                if (period.Start <= currentDateTime) // TODO make comparison using day count function?
                {
                    throw new ArgumentException($"All elements of {simulatedPeriods} must start after {currentDateTime}.", nameof(simulatedPeriods));
                }

                if (i > 0)
                {
                    T lastPeriod = simulatedPeriodsArray[i - 1];
                    if (period.CompareTo(lastPeriod) < 0)
                    {
                        throw new ArgumentException(nameof(simulatedPeriods) + " argument must be sorted in ascending order.", nameof(simulatedPeriods));
                    }
                    if (period.Equals(lastPeriod))
                    {
                        throw new ArgumentException(nameof(simulatedPeriods) + $" argument cannot contain duplicated elements. More than one element with value {period} found.", nameof(simulatedPeriods));
                    }
                }

                if (!forwardCurve.TryGetValue(period, out double forwardPrice))
                {
                    throw new ArgumentException($"Forward curve does not contain price for period {period}.", nameof(forwardCurve));
                }

                _forwardPrices[i] = forwardPrice;

                double timeToMaturity = timeFunc(currentDateTime, period.Start);
                double timeIncrement  = timeToMaturity - timeToMaturityPrevious;

                for (int j = 0; j < numFactors; j++)
                {
                    Factor <T> factor = modelParameters.Factors[j];
                    _spotVols[i, j]             = factor.Volatility[period]; // TODO check if period in volatility
                    _reversionMultipliers[i, j] = Math.Exp(-factor.MeanReversion * timeIncrement);
                }

                _factorCovarianceSquareRoots[i] = CalcFactorCovarianceSquareRoots(modelParameters, timeIncrement);

                _driftAdjustments[i] = CalcDriftAdjustment(modelParameters, timeToMaturity, period);

                timeToMaturityPrevious = timeToMaturity;
            }
        }