| 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
|
|