⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copularnd.m

📁 copua是金融数学计算中的一类新模型。本代码提供了最常用的copula模型
💻 M
字号:
function u = copularnd(type,varargin)
%COPULARND Random values from a copula.
%   U = COPULARND('Gaussian',RHO,N) returns a matrix U of random values
%   generated from a Gaussian copula with correlation parameter RHO.  Each
%   column of U comes from a Uniform(0,1) marginal distribution.  If RHO is
%   a scalar correlation coefficient, U is an N-by-2 matrix generated from
%   a bivariate Gaussian copula.  If RHO is a P-by-P correlation matrix, U
%   is an N-by-P matrix generated from a P-variate Gaussian copula.
%
%   U = COPULARND('t',RHO,NU,N) returns a matrix U of random values
%   generated from a t copula with correlation parameter RHO and degrees of
%   freedom NU.  Each column of U comes from a Uniform(0,1) marginal
%   distribution. If RHO is a scalar correlation coefficient, U is an
%   N-by-2 matrix generated from a bivariate t copula.  If RHO is a P-by-P
%   correlation matrix, U is an N-by-P matrix generated from a P-variate t
%   copula.
%
%   U = COPULARND(TYPE,ALPHA,N) returns an N-by-2 matrix of random values
%   generated from the bivariate Archimedean copula with parameter ALPHA.
%   TYPE is one of 'Clayton', 'Frank', or 'Gumbel'.  Each column of U comes
%   from a Uniform(0,1) marginal distribution.
%
%   Example:
%      % Determine the linear correlation coefficient corresponding to a
%      % bivariate Gaussian copula having a rank correlation of -0.5
%      tau = -0.5
%      rho = copulaparam('gaussian',tau)
%
%      % Generate dependent beta random values using that copula
%      u = copularnd('gaussian',rho,100)
%      b = betainv(u,2,2)
%
%      % Verify that those pairs have a sample rank correlation approximately
%      % equal to tau
%      tau_sample = kendall(b)

%   Written by Peter Perkins, The MathWorks, Inc.
%   Revision: 1.0  Date: 2003/09/05
%   This function is not supported by The MathWorks, Inc.
%
%   Requires MATLAB R13, including the Statistics Toolbox.


switch lower(type)

% Elliptical copulas
%
% Random vectors from these copulas can be generated by creating random
% vectors from the multivariate normal (or t) distribution, then
% transforming them to uniform marginals using the normal (or t) CDF.
case 'gaussian'
    if nargin < 3
        error('Requires three input arguments for the Gaussian copula.');
    end
    rho = varargin{1};
    n = varargin{2};
    if numel(rho) == 1
        if (rho < -1 | 1 < rho)
            error('RHO must be a correlation coefficient between -1 and 1, or a positive semidefinite correlation matrix.');
        end
        u = normcdf(mvnrnd([0 0],[1 rho; rho 1],n));
    else
        if ~iscor(rho)
            error('RHO must be a correlation coefficient between -1 and 1, or a positive semidefinite correlation matrix.');
        end
        p = size(rho,1);
        u = normcdf(mvnrnd(zeros(1,p),rho,n));
    end

case 't'
    if nargin < 4
        error('Requires four input arguments for the t copula.');
    end
    rho = varargin{1};
    nu = varargin{2};
    n = varargin{3};
    if ~(0 < nu)
        error('NU must be positive for the t copula.');
    end
    if numel(rho) == 1
        if (rho < -1 | 1 < rho)
            error('RHO must be a correlation coefficient between -1 and 1, or a positive semidefinite correlation matrix.');
        end
        u = tcdf(mvtrnd([1 rho; rho 1],nu,n),nu);
    else
        if ~iscor(rho)
            error('RHO must be a correlation coefficient between -1 and 1, or a positive semidefinite correlation matrix.');
        end
        u = tcdf(mvtrnd(rho,nu,n),nu);
    end

% Archimedean copulas
%
% Random pairs from these copulae can be generated sequentially: first
% generate u1 as a uniform r.v.  Then generate u2 from the conditional
% distribution F(u2 | u1; alpha) by generating uniform random values, then
% inverting the conditional CDF.
case {'clayton' 'frank' 'gumbel'}
    if nargin < 3
        error('Requires three input arguments for an Archimedean copula.');
    end
    alpha = varargin{1};
    if numel(alpha) ~= 1
        error('ALPHA must be a scalar.');
    end
    
    switch lower(type)
    case 'clayton'
        if alpha < 0
            error('ALPHA must be nonnegative for the Clayton copula.');
        end
        n = varargin{2};
        u1 = rand(n,1);
        % The inverse conditional CDF has a closed form for this copula.
        p = rand(n,1);
        if alpha > sqrt(eps)
            u2 = u1.*(p.^(-alpha./(1+alpha)) - 1 + u1.^alpha).^(-1./alpha);
        else
            u2 = p;
        end
        u = [u1 u2];

    case 'frank'
        n = varargin{2};
        u1 = rand(n,1);
        % The inverse conditional CDF has a closed form for this copula.
        p = rand(n,1);
        if abs(alpha) > log(realmax)
            u2 = (u1 < 0) + sign(alpha).*u1; % u1 or 1-u1
        elseif abs(alpha) > sqrt(eps)
            u2 = -log((exp(-alpha.*u1).*(1-p)./p + exp(-alpha))./(1 + exp(-alpha.*u1).*(1-p)./p))./alpha;
%             u2 = -log(1 + (1-exp(alpha))./(exp(alpha) + exp(alpha.*(1-u1)).*(1-p)./p))./alpha;
        else
            u2 = p;
        end
        u = [u1 u2];

    case 'gumbel'
        if alpha < 1
            error('ALPHA must be greater than or equal to 1 for the Gumbel copula.');
        end
        n = varargin{2};
        u1 = rand(n,1);
        % The inverse conditional CDF does not have a closed form for this
        % copula.  The inversion must be done numerically.
        p = rand(n,1);
        u2 = condCDFinv(@gumbelCondCDF,u1,p,alpha);
        u = [u1 u2];
    end

otherwise
    error('Unrecognized copula type: ''%s''',type);
end


function p = gumbelCondCDF(u1,u2,alpha)
%GUMBELCONDCDF Conditional distribution function for the Gumbel copula.
%   P = gumbelCondCDF(U,ALPHA) returns the conditional cumulative distibution
%   function of U2, given U1, for the Gumbel copula.
% logC = -((-log(u1)).^alpha + (-log(u2)).^alpha).^(1./alpha);
nlog1 = -log(u1);
nlog2 = -log(u2);
maxlog = max(nlog1,nlog2);
logC = -maxlog .* ((nlog1./maxlog).^alpha + (nlog2./maxlog).^alpha).^(1./alpha);
p = (-nlog1./logC).^(alpha-1) .* exp(logC)./u1;


function u2 = condCDFinv(condCDF,u1,p,alpha)
%CONDCDFINV Inverse conditional distribution function
%   U2 = CONDCDFINV(CONDCDF,U1,P,ALPHA) returns U2 such that
%
%      CONDCDF(U1,U2,ALPHA) = P,
%
%  where CONDCDF is a function handle to a function that computes the
%  conditional cumulative distribution function of U2 given U1, for an
%  archimedean copula with parameter ALPHA.
%
% CONDCDFINV uses a simple binary chop search.  Newton's method or the
% secant method would probably be faster.

lower = zeros(size(p));
upper = ones(size(p));
width = 1;
tol = 1e-12;
while width > tol
    u2 = .5 .* (lower + upper);
    lo = feval(condCDF,u1,u2,alpha) < p;
    lower(lo) = u2(lo);
    upper(~lo) = u2(~lo);
    width = .5 .* width;
end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -