function [SwaptionTree, SwapHWTree] = trintree_swaption_HW(U, Curve, opt_type, model, a)
% 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.
% 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'
% 'swap' (no option)
% model :
% 'EV' (extended Vasicek)
% 'BK' (Black-Karasinski)
% a : parameter vector (3 dim vector)
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-flowadjustments
%--------------------------------------------------------------
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
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 matching portfolio cash-flow times
%--------------------------------------------------------
switch model
case 'EV'
T_plus=addtodate(T(end),3,'month');% let the Tree end at the max coupon date
TimeSpec=hwtimespec(oggi,[T(2:end);T_plus],Curve.Compounding);
TimeSpec.Basis=Basis(i);
RateSpec=Curve.toRateSpec([T(2:end);T_plus]);
VolSpec = hwvolspec(Curve.Settle, [Curve.Settle;T_plus],...
abs(a(1:2)),T_plus, a(3));
Tree=hwtree(VolSpec,RateSpec,TimeSpec,'method','HW2000');
case 'BK'
T_plus=addtodate(T(end),3,'month');% let the Tree end at the max coupon date
TimeSpec=bktimespec(oggi,[T(2:end);T_plus],Curve.Compounding);
TimeSpec.Basis=Basis(i);
RateSpec=Curve.toRateSpec([T(2:end);T_plus]);
VolSpec = bkvolspec(Curve.Settle, [Curve.Settle;T_plus],...
abs(a(1:2)),T_plus, a(3));
Tree=bktree(VolSpec,RateSpec,TimeSpec,'method','HW2000');
otherwise
return
end
%--------------------------------------------------------
% Begin the pricing iterations
%--------------------------------------------------------
[~,~,Status]=trintreeshape(Tree);
tk=length(Status);
SwapTree = mktrintree(tk,1,Status(1:tk),0);
SwapTree2 = mktrintree(tk,1,Status(1:tk),0);
for j=tk:-1:2
Probs=zeros([Status(j-1) Status(j)]);
iMat=sub2ind([Status(j-1) Status(j)],repmat((1:Status(j-1))',1,3),...
[Tree.Connect{j-1}'-1, Tree.Connect{j-1}', Tree.Connect{j-1}'+1]);
Probs(iMat)=Tree.Probs{j-1}';
Bond=1./Tree.FwdTree{j-1};
FloatCpn=(Tree.FwdTree{j-1}-1)/(Tree.tObs(j)-Tree.tObs(j-1));
%FloatLeg=(CFlowT(:,j)*FTree.RateTree{j-1})';% no need of alpha here because already fixed in cfamounts
FloatLeg=(CFlowT(:,j)*FloatCpn)';% no need of alpha here because already fixed in cfamounts
FixedLeg=repmat((CFlowT(:,j).*FixCpn(i))',Status(j-1),1);
SwapTree2(j-1)={(Probs*SwapTree2{j}'-(FloatLeg-FixedLeg))'.*Bond};
switch opt_type
case 'vanilla'
% generate the state-matrix via backward induction
% the first term is the expected present value of the state vector at time t-1,
% representing the swap value at time t+1. The second term is the expected
% present value of the coupon fraction cash-flow at time t+1
SwapTree(j-1)={(Probs*SwapTree{j}'-(FloatLeg-FixedLeg))'.*Bond};
% adjust the backward induction procedure to determine the tree for a swaption portfolio
swaption_op=1-(repmat((FwdDates==T(j-1)),1,Status(j-1)) & SwapTree2{j-1}<=0);
SwapTree(j-1)={SwapTree2{j-1}.*swaption_op};
case 'bermudan'
SwapTree(j-1)={(Probs*SwapTree{j}'-(FloatLeg-FixedLeg))'.*Bond};
% adjust the backward induction procedure to determine the tree for a swaption portfolio
swaption_op=1-(repmat((FwdDates<=T(j-1)),1,Status(j-1)) & SwapTree2{j-1}<=0);
SwapTree(j-1)={max([SwapTree{j-1};SwapTree2{j-1}.*swaption_op])};
case 'swap'
SwapTree(j-1)={(Probs*SwapTree{j}'-(FloatLeg-FixedLeg))'.*Bond};
otherwise
return
end
end
% cut the dead branches
SwapTree(end)=[];
% output
SwaptionTree(i)={SwapTree};
SwapHWTree(i)={Tree};
end
end