Code covered by the BSD License  

Highlights from
Trinomial tree seaption pricing

Trinomial tree seaption pricing

by

 

Swaption pricing function under the Hull-White lattice model. It allows finer grid.

trintree_swaption_plus_HW(U, Curve, opt_type, model, a, d_aug)
function [SwaptionTree, SwapHWTree] = trintree_swaption_plus_HW(U, Curve, opt_type, model, a, d_aug)


% This function generates the Swaption price, from a portfolio
% of underlying swaps' cash-flow. The Bermudian type swaptions are
% can be exercised at the underlying cash-flow dates. The cash-flow
% structure allows varying notionals, but only the first and last coupon
% might be irregular. 

% This function allows for a finer time-grid.

% Reminder: this swap pricing function includes the fraction
% of the current coupon if the settlement is the start date
% the floating leg is determined by the current fwd rate.
% The function cannot determine fwd rates back in the past
% (i.e. before the settlement). If the running coupon
% is to be excluded, just set the start date fwd. The cash-flow
% stream is basically determined by the Maturity time.

% The option exposure is assumed to be long (option buyer) with the convention that
% a negative fixed leg cash-flow (fix payer) entails call option exposure. 
% On the other side, a positive fixed leg cash-flow (fix reciever) is associated
% to a long put swaption exposure.
%
% input
% U : code, date, principal, coupon, basis, period.
% Curve : interest rate curve object
% opt_type : 
%       'vanilla'
%       'bermudan'
%	'american'
%       'swap' (no option)
% model :
%       'EV' (extended Vasicek)
%       'BK' (Black-Karasinski)
% a : parameter vector (3 dim vector)
% d_aug : number of time-points between cash-flow dates

if d_aug<=1, 
    disp('The days augmentation factor must be greater than 1')
    return, 
end

items=unique(U(:,1));
n_item=size(items,1);
CouponRate=cell(size(items));
Principal=cell(size(items));
oggi=Curve.Settle;
Maturity=zeros(size(items));
Basis=zeros(size(items));
Period=zeros(size(items));
EndMonthRule=0;
Face=ones(size(items)); % fictious notional to allow irregular cash-flows
Settle=zeros(size(items));
StartDate=zeros(size(items));
FstCpnDate=zeros(size(items));
LstCpnDate=zeros(size(items));
FixCpn=zeros(size(items));
SwaptionTree=cell(n_item,1);
SwapHWTree=cell(n_item,1);

%--------------------------------------------------------------
% generate the cash-flow matrix
%--------------------------------------------------------------
for i=1:n_item

	H=U(U(:,1)==items(i),:);
    [~,u]=sort(H(:,2));
    H=H(u,:);
    StartDate(i)=H(1,2);
    Settle(i)=max(oggi,H(1,2));
    H(1,:)=[]; % it assumes that the cash-flow portfolio contains the (empty) cash-flow start
    CouponRate(i)={[H(:,2),H(:,3)]}; % matrix: [dates, coupon]
    Principal(i)={[H(:,2),H(:,3)]}; % matrix: [dates, coupon]
    Maturity(i)=H(end,2);
    Basis(i)=H(1,5);
    Period(i)=H(1,6);
    FstCpnDate(i)=H(1,2);
    LstCpnDate(i)=H(end,2);
    FixCpn(i)=H(1,4)/100;
    
end

[CFlowAmounts, CFlowDates, ~, ~, CFPrincipal]= cfamounts(CouponRate, Settle,Maturity,...
    'StartDate',StartDate,'FirstCouponDate',FstCpnDate,'LastCouponDate',...
    LstCpnDate,'Face',Face,'Basis',Basis,...
    'EndMonthRule',EndMonthRule,'BusinessDayConvention','previous','Period',Period);%<<--------------------------------------

%--------------------------------------------------------------
% cash-flow adjustments
%--------------------------------------------------------------

CFlowAmounts=CFlowAmounts-CFPrincipal; % this assumes that CF is stripped
CFlowAmounts(:,2)=CFlowAmounts(:,2)+CFlowAmounts(:,1); % this assumes that if the first coupon is irregular it is paid in stub
CFlowAmounts(:,1)=0; % it zeroes the accrued interest
u=CFlowDates(:,2)==oggi;
CFlowAmounts(u,2)=nan;
CFlowDates(u,2)=nan;

%--------------------------------------------------------------
% begin iterations
%--------------------------------------------------------------

for i=1:n_item

    disp('----------------------------------------')
    disp(['processing item n ',num2str(i)])
    if CFlowDates(i,1)==oggi,
        T=CFlowDates(i,~isnan(CFlowDates(i,:)))';
        CFlowT=CFlowAmounts(i,~isnan(CFlowDates(i,:)));
        if strcmp(opt_type,'bermudan')
            % if the settlement date is greater than the first historical option date
            % we need to adjust the cash-flow stream in order to exclude a swap payment
            % which cannot be part of the Bermudian structure.
            FwdDates=T(2);
            CFlowT(i,2)=0;
        else
            % otherwise, the vanilla option is just an ordinary swap
            FwdDates=0;
        end
    else
        FwdDates=CFlowDates(i,1);
        T=[oggi;CFlowDates(i,~isnan(CFlowDates(i,:)))'];
        CFlowT=[0,CFlowAmounts(i,~isnan(CFlowDates(i,:)))];
    end
    %----------------------------------------------------------
    % Generate the tree inflating the portfolio cash-flow times
    %----------------------------------------------------------

    T_plus=addtodate(T(end),3,'month');% let the Tree end 3 months later than the max coupon date
    q=floor(daysdif(T,[T(2:end);T_plus],Curve.Basis)/d_aug);
    qq=(repmat(T,1,d_aug)+q*(0:d_aug-1))';
    TT=[qq(:);T_plus];
    
    switch model
        
        case 'EV'
            TimeSpec=hwtimespec(oggi,TT(2:end),Curve.Compounding);
            TimeSpec.Basis=Basis(i);
            RateSpec=Curve.toRateSpec(TT(2:end));
            VolSpec = hwvolspec(Curve.Settle, [Curve.Settle;TT(end)],...
                abs(a(1:2)),TT(end), a(3));
            Tree=hwtree(VolSpec,RateSpec,TimeSpec,'method','HW2000');
        case 'BK'
            TimeSpec=bktimespec(oggi,TT(2:end),Curve.Compounding);
            TimeSpec.Basis=Basis(i);
            RateSpec=Curve.toRateSpec(TT(2:end));
            VolSpec = bkvolspec(Curve.Settle, [Curve.Settle;TT(end)],...
                abs(a(1:2)),TT(end), a(3));
            Tree=bktree(VolSpec,RateSpec,TimeSpec,'method','HW2000');
        otherwise
            return
    end

    %--------------------------------------------------------
    % Begin the pricing iterations
    %--------------------------------------------------------

    [~,~,Status]=trintreeshape(Tree);
    [~,ia]=ismember(T,TT);
    tk=length(T);
    SwapState = cell(tk,1);
    SwapState(end)={zeros(Status(ia(end)),1)};%%<<------------------------------
    SwaptState = cell(tk,1);
    SwaptState(end)={zeros(Status(ia(end)),1)};%%<<------------------------------

        for j=tk:-1:2
            
            statn=Status(ia(j-1));
            StartDate=T(j-1);
            EndDate=T(j);
            SwapState(j-1)={zeros(Status(ia(j-1)),1)};
            SwaptState(j-1)={zeros(Status(ia(j-1)),1)};
            
            for s=1:statn
                
                [Branch, connect0]=subtree_branch(Tree, StartDate, EndDate, s );
                [SwapState{j-1}(s), SwaptState{j-1}(s)]=subtree_bwd_induction( Branch, SwapState{j}(connect0(1)-1:connect0(end)+1),...
                    SwaptState{j}(connect0(1)-1:connect0(end)+1), CFlowT(j), FixCpn(i) );
                
            end

        end
    % cut the dead branches
    SwapState(end)=[];
    % output
    SwaptionTree(i)={SwapState};
    SwapHWTree(i)={Tree};
        
end

    function [SubTree, connect, t0] = subtree_branch(BTree, StartDate, EndDate, ki )

        compound = BTree.TimeSpec.Compounding;
        basis = BTree.TimeSpec.Basis;
        Time=[BTree.TimeSpec.ValuationDate;BTree.TimeSpec.Maturity];
        ti0 = find(Time==StartDate); 
        ti1 = find(Time==EndDate); 

        SubTree=struct;
        SubTree.FinObj='HWFwdTree';
        SubTree.VolSpec=struct([]);
        SubTree.TimeSpec=struct([]);
        SubTree.RateSpec=struct([]);
        SubTree.tObs=[];
        SubTree.dObs=[];
        SubTree.CFlowT=cell(0);
        SubTree.Probs=cell(0);
        SubTree.Connect=cell(0);
        SubTree.FwdTree=cell(0);

        k=ti0;
        jj=1;
        tObs=date2time(Time(ti0),Time(ti0+1:ti1),compound,basis);
        SubTree.Connect(jj)={2};
        SubTree.Probs(jj)={BTree.Probs{ti0}(:,ki)};
        SubTree.FwdTree(jj)={BTree.FwdTree{ti0}(ki)};
        SubTree.CFlowT(jj)={tObs(jj:end)};

        connect=BTree.Connect{ti0}(ki);
        k=k+1;
        jj=jj+1;
        while k<=(ti1-1)

            SubTree.Probs(jj)={BTree.Probs{k}(:,connect(1)-1:connect(end)+1)};
            SubTree.FwdTree(jj)={BTree.FwdTree{k}(connect(1)-1:connect(end)+1)};
            connect = BTree.Connect{k}(connect(1)-1:connect(end)+1);
            SubTree.Connect(jj)={connect-connect(1)+2};
            SubTree.CFlowT(jj)={tObs(jj:end)};
            k=k+1;
            jj=jj+1;

        end
        % we let the subtree include the last state vector of the fwd process
        % this is in contrast with the tree construction procedure of the 
        % financial instruments Matlab function. The output tree cannot be
        % used within the Matlab utility functions.
        SubTree.FwdTree(jj)={BTree.FwdTree{k}(connect(1)-1:connect(end)+1)};
        SubTree.tObs=date2time(Time(ti0),Time(ti0:ti1-1),compound,basis);
        SubTree.dObs=Time(ti0:ti1-1);
        SubTree.TimeSpec=bktimespec(Time(ti0),Time(ti0+1:ti1),compound);
        SubTree.TimeSpec.Basis=basis;
        % we need to take out of the function the vectors of connection at the last state vector
        %connect = BTree.Connect{k-1}(connect(1)-1:connect(end)+1);
        t0=Time(ti0);
        
    end

    function [X0, X1] = subtree_bwd_induction( ZTree, term_cond0, term_cond1, SubCFlow, SubFixCpn )

        [~,~,SubStatus]=trintreeshape(ZTree);
        tkk=length(SubStatus);
        WTree0 = mktrintree(tkk,1,SubStatus(1:tkk),0);
        WTree1 = mktrintree(tkk,1,SubStatus(1:tkk),0);
        % convert the fwd-factors tree into the fwd-rates tree
        SubFloatCpn=(ZTree.FwdTree{1}-1)/ZTree.CFlowT{1}(1);
        FloatLeg=SubCFlow*SubFloatCpn;% no need of alpha here because already fixed in cfamounts
        FixedLeg=SubCFlow.*SubFixCpn;
        WTree0(end)={(term_cond0-(FloatLeg-FixedLeg))'};%%<<------------------------------
        WTree1(end)={(term_cond1-(FloatLeg-FixedLeg))'};%%<<------------------------------

        for jj=tkk:-1:2

            Probs=zeros([SubStatus(jj-1) SubStatus(jj)]);
            iMat=sub2ind([SubStatus(jj-1) SubStatus(jj)],repmat((1:SubStatus(jj-1))',1,3),...
                [ZTree.Connect{jj-1}'-1, ZTree.Connect{jj-1}', ZTree.Connect{jj-1}'+1]);
            Probs(iMat)=ZTree.Probs{jj-1}';
            Bond=1./ZTree.FwdTree{jj-1};
            WTree0(jj-1)={(Probs*WTree0{jj}')'.*Bond};
            WTree1(jj-1)={(Probs*WTree1{jj}')'.*Bond};
            if strcmp(opt_type,'american'), 
                % adjust the backward induction procedure to determine the tree for a swaption portfolio
                swaption_op=1-(repmat((FwdDates<=ZTree.dObs(jj-1)),1,SubStatus(jj-1)) & WTree0{jj-1}<=0);
                WTree1(jj-1)={max([WTree1{jj-1};WTree0{jj-1}.*swaption_op])};% the American algorithm
            end

        end
        
        switch opt_type
            case 'vanilla'
                % adjust the backward induction procedure to determine the tree for a swaption portfolio
                swaption_op=1-(repmat((FwdDates==ZTree.dObs(jj-1)),1,SubStatus(jj-1)) & WTree0{jj-1}<=0);
                WTree1(jj-1)={WTree0{jj-1}.*swaption_op};
            case 'bermudan'
                % adjust the backward induction procedure to determine the tree for a swaption portfolio
                swaption_op=1-(repmat((FwdDates<=ZTree.dObs(jj-1)),1,SubStatus(jj-1)) & WTree0{jj-1}<=0);
                WTree1(jj-1)={max([WTree1{jj-1};WTree0{jj-1}.*swaption_op])};% the American algorithm
            case 'american'
                % do nothing
            case 'swap'
                % do nothing
            otherwise
                return
        end
        X0=WTree0{1};
        X1=WTree1{1};

    end

end

Contact us