Files
Work/cashflow/CASHFLOW.CPP
2024-08-07 09:12:07 -04:00

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();
}