164 lines
6.4 KiB
C++
164 lines
6.4 KiB
C++
#include <cashflow/cashflow.hpp>
|
|
|
|
WORD CashFlow::generateCashFlows(const PurePassThru &purePassThru,Block<PureCashFlow> &cashFlows)
|
|
{
|
|
double issBal(purePassThru.issBal());
|
|
double tempCPR;
|
|
short actualMonth;
|
|
short indexFlows;
|
|
|
|
cashFlows.remove();
|
|
indexFlows=cashFlows.size();
|
|
cashFlows.insert(&PureCashFlow());
|
|
for(short wam=purePassThru.wam();wam>0&&issBal>0.00;wam--)
|
|
{
|
|
actualMonth=(purePassThru.origTerm()-wam)+1;
|
|
if(actualMonth<=30)tempCPR=.002*(double)actualMonth;
|
|
else tempCPR=.06;
|
|
cashFlows[indexFlows].beginBal(issBal);
|
|
cashFlows[indexFlows].smm(1.00-::pow(1.00-(tempCPR*purePassThru.psa()/100.00),1.00/12.00));
|
|
if(!indexFlows)
|
|
{
|
|
cashFlows[indexFlows].mtgPay((issBal*(purePassThru.wac()/1200.00))/
|
|
(1.00-::pow(1.00/(1.00+(purePassThru.wac()/1200.00)),(double)wam)));
|
|
}
|
|
else cashFlows[indexFlows].mtgPay(cashFlows[indexFlows-1].mtgPay());
|
|
if(issBal<=cashFlows[indexFlows].mtgPay())cashFlows[indexFlows].mtgPay(issBal);
|
|
cashFlows[indexFlows].netIntPay(issBal*(purePassThru.coupon()/1200.00));
|
|
if(!indexFlows)cashFlows[indexFlows].grossIntPay(cashFlows[indexFlows].netIntPay());
|
|
else cashFlows[indexFlows].grossIntPay(cashFlows[indexFlows-1].grossIntPay()+cashFlows[indexFlows].netIntPay());
|
|
cashFlows[indexFlows].schedPrinPay(cashFlows[indexFlows].mtgPay()-cashFlows[indexFlows].netIntPay());
|
|
cashFlows[indexFlows].prepayment(0.00);
|
|
cashFlows[indexFlows].totPrin(cashFlows[indexFlows].schedPrinPay()+cashFlows[indexFlows].prepayment());
|
|
cashFlows[indexFlows].cashFlow(cashFlows[indexFlows].netIntPay()+cashFlows[indexFlows].totPrin());
|
|
cashFlows[indexFlows].factor(issBal/purePassThru.issBal());
|
|
issBal-=cashFlows[indexFlows].totPrin();
|
|
indexFlows=cashFlows.size();
|
|
if(1!=wam&&issBal>0.00)cashFlows.insert(&PureCashFlow());
|
|
}
|
|
return cashFlows.size();
|
|
}
|
|
|
|
WORD CashFlow::generateCashFlows(const PurePassThru &purePassThru,Block<PureCashFlow> &cashFlows,PrePay prePay)
|
|
{
|
|
double issBal(purePassThru.issBal());
|
|
double tempCPR;
|
|
short actualMonth;
|
|
short indexFlows;
|
|
|
|
cashFlows.remove();
|
|
indexFlows=cashFlows.size();
|
|
cashFlows.insert(&PureCashFlow());
|
|
for(short wam=purePassThru.wam();wam>0&&issBal>0.00;wam--)
|
|
{
|
|
actualMonth=(purePassThru.origTerm()-wam)+1;
|
|
if(actualMonth<=30)tempCPR=.002*(double)actualMonth;
|
|
else tempCPR=.06;
|
|
cashFlows[indexFlows].beginBal(issBal);
|
|
cashFlows[indexFlows].smm(1.00-::pow(1.00-(tempCPR*purePassThru.psa()/100.00),1.00/12.00));
|
|
if(!indexFlows)cashFlows[indexFlows].mtgPay((issBal*(purePassThru.wac()/1200.00))/
|
|
(1.00-::pow(1.00/(1.00+(purePassThru.wac()/1200.00)),(double)wam)));
|
|
else cashFlows[indexFlows].mtgPay(cashFlows[indexFlows-1].mtgPay());
|
|
if(issBal<=cashFlows[indexFlows].mtgPay())cashFlows[indexFlows].mtgPay(issBal);
|
|
cashFlows[indexFlows].netIntPay(issBal*(purePassThru.coupon()/1200.00));
|
|
if(!indexFlows)cashFlows[indexFlows].grossIntPay(cashFlows[indexFlows].netIntPay());
|
|
else cashFlows[indexFlows].grossIntPay(cashFlows[indexFlows-1].grossIntPay()+cashFlows[indexFlows].netIntPay());
|
|
cashFlows[indexFlows].schedPrinPay(cashFlows[indexFlows].mtgPay()-cashFlows[indexFlows].netIntPay());
|
|
cashFlows[indexFlows].prepayment(prePay.amount());
|
|
prePay.period(prePay.period()+1);
|
|
if(prePay.period()>prePay.frequency())
|
|
{
|
|
prePay.amount(prePay.amount()+prePay.increment());
|
|
prePay.period(1);
|
|
}
|
|
cashFlows[indexFlows].totPrin(cashFlows[indexFlows].schedPrinPay()+cashFlows[indexFlows].prepayment());
|
|
cashFlows[indexFlows].cashFlow(cashFlows[indexFlows].netIntPay()+cashFlows[indexFlows].totPrin());
|
|
cashFlows[indexFlows].factor(issBal/purePassThru.issBal());
|
|
issBal-=cashFlows[indexFlows].totPrin();
|
|
indexFlows=cashFlows.size();
|
|
if(1!=wam&&issBal>0.00)cashFlows.insert(&PureCashFlow());
|
|
}
|
|
return cashFlows.size();
|
|
}
|
|
|
|
WORD CashFlow::convergePSA(PurePassThru &purePassThru,double convergeFactor,double issueBal,short runMonths)
|
|
{
|
|
double cashFlowFactor;
|
|
double smallestDiff(999);
|
|
double tempDiff;
|
|
short closestPSA;
|
|
|
|
for(short psaValue=MinPSA;psaValue<MaxPSA;psaValue++)
|
|
{
|
|
purePassThru.psa(psaValue);
|
|
cashFlowFactor=factorFlows(purePassThru,issueBal,runMonths);
|
|
tempDiff=convergeFactor-cashFlowFactor;
|
|
if(tempDiff<0.00)tempDiff*=-1.00;
|
|
if(tempDiff<smallestDiff){smallestDiff=tempDiff;closestPSA=psaValue;}
|
|
}
|
|
return closestPSA;
|
|
}
|
|
|
|
WORD CashFlow::binaryPartitionPSA(PurePassThru &purePassThru,double convergeFactor,double issueBal,short runMonths)
|
|
{
|
|
double cashFlowFactor;
|
|
short psaFloor(MinPSA);
|
|
short psaCeiling(MaxPSA);
|
|
short psaCurr(MaxPSA/2);
|
|
short newCurr;
|
|
double threshold(.000025);
|
|
|
|
while(TRUE)
|
|
{
|
|
purePassThru.psa(psaCurr);
|
|
cashFlowFactor=factorFlows(purePassThru,issueBal,runMonths);
|
|
if(cashFlowFactor-threshold<=convergeFactor&&cashFlowFactor+threshold>=convergeFactor)return psaCurr;
|
|
if(cashFlowFactor>convergeFactor)
|
|
{
|
|
psaFloor=psaCurr;
|
|
newCurr=(psaCeiling+psaFloor)/2;
|
|
}
|
|
else
|
|
{
|
|
psaCeiling=psaCurr;
|
|
newCurr=(psaFloor+psaCeiling)/2;
|
|
}
|
|
if(newCurr==psaCurr)return psaCurr;
|
|
psaCurr=newCurr;
|
|
}
|
|
}
|
|
|
|
double CashFlow::factorFlows(const PurePassThru &purePassThru,double issueBalance,short runMonths)
|
|
{
|
|
double issBal(purePassThru.issBal());
|
|
Block<PureCashFlow> cashFlows;
|
|
double tempCPR;
|
|
short actualMonth;
|
|
short indexFlows;
|
|
|
|
indexFlows=cashFlows.size();
|
|
cashFlows.insert(&PureCashFlow());
|
|
for(short wam=purePassThru.wam();wam>=purePassThru.wam()-runMonths;wam--)
|
|
{
|
|
actualMonth=(purePassThru.origTerm()-wam)+1;
|
|
if(actualMonth<=30)tempCPR=.002*(double)actualMonth;
|
|
else tempCPR=.06;
|
|
cashFlows[indexFlows].beginBal(issBal);
|
|
cashFlows[indexFlows].smm(1.00-::pow(1.00-(tempCPR*purePassThru.psa()/100.00),1.00/12.00));
|
|
cashFlows[indexFlows].mtgPay((issBal*(purePassThru.wac()/1200.00))/
|
|
(1.00-::pow(1.00/(1.00+(purePassThru.wac()/1200.00)),(double)wam)));
|
|
cashFlows[indexFlows].netIntPay(issBal*(purePassThru.coupon()/1200.00));
|
|
cashFlows[indexFlows].grossIntPay(issBal*(purePassThru.wac()/1200.00));
|
|
cashFlows[indexFlows].schedPrinPay(cashFlows[indexFlows].mtgPay()-cashFlows[indexFlows].grossIntPay());
|
|
cashFlows[indexFlows].prepayment(cashFlows[indexFlows].smm()*(issBal-cashFlows[indexFlows].schedPrinPay()));
|
|
cashFlows[indexFlows].totPrin(cashFlows[indexFlows].schedPrinPay()+cashFlows[indexFlows].prepayment());
|
|
cashFlows[indexFlows].cashFlow(cashFlows[indexFlows].netIntPay()+cashFlows[indexFlows].totPrin());
|
|
cashFlows[indexFlows].factor(issBal/issueBalance);
|
|
issBal-=cashFlows[indexFlows].totPrin();
|
|
indexFlows=cashFlows.size();
|
|
if(1!=wam)cashFlows.insert(&PureCashFlow());
|
|
}
|
|
return cashFlows[runMonths].factor();
|
|
}
|
|
|