Skip to content

Commit

Permalink
Add unit tests for utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
gandhis1 committed Oct 6, 2019
1 parent 203ba9c commit 3849f6c
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 58 deletions.
4 changes: 2 additions & 2 deletions src/engine/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ const char *PrettyDescriptionScenario(Scenario *scenario)
return strdup(scenario->prettyDescription().c_str());
}

Loan *CreateLoan(const char *loanId, double originalBalance, double currentBalance, struct tm factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, int currentLoanAge, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, const char *originalPrepaymentString)
Loan *CreateLoan(const char *loanId, double originalBalance, double currentBalance, struct tm firstPaymentDate, struct tm factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, const char *originalPrepaymentString)
{
return new Loan(loanId, originalBalance, currentBalance, factorDate, originalLoanTerm, originalAmortTerm, originalIOTerm, currentLoanAge, grossCoupon, feeStrip, accrualBasis, originalPrepaymentString);
return new Loan(loanId, originalBalance, currentBalance, firstPaymentDate, factorDate, originalLoanTerm, originalAmortTerm, originalIOTerm, grossCoupon, feeStrip, accrualBasis, originalPrepaymentString);
}
void DeleteLoan(Loan *loan)
{
Expand Down
2 changes: 1 addition & 1 deletion src/engine/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extern "C"
EXPORT void DeleteScenario(Scenario *scenario);
EXPORT const char *PrettyDescriptionScenario(Scenario *scenario);

EXPORT Loan *CreateLoan(const char *loanId, double originalBalance, double currentBalance, struct tm factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, int currentLoanAge, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, const char *originalPrepaymentString);
EXPORT Loan *CreateLoan(const char *loanId, double originalBalance, double currentBalance, struct tm firstPaymentDate, struct tm factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, const char *originalPrepaymentString);
EXPORT void DeleteLoan(Loan *loan);
EXPORT const char *PrettyDescriptionLoan(Loan *loan);

Expand Down
5 changes: 3 additions & 2 deletions src/engine/loan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
Loan::Loan(std::string id,
double originalBalance,
double currentBalance,
struct tm firstPaymentDate,
struct tm factorDate,
int originalLoanTerm,
int originalAmortTerm,
int originalIOTerm,
int currentLoanAge,
double grossCoupon,
double feeStrip,
AccrualBasis accrualBasis,
Expand All @@ -23,17 +23,18 @@ Loan::Loan(std::string id,
int accrualStartDay) : id(id),
originalBalance(originalBalance),
currentBalance(currentBalance),
firstPaymentDate(firstPaymentDate),
factorDate(factorDate),
originalLoanTerm(originalLoanTerm),
originalAmortTerm(originalAmortTerm),
originalIOTerm(originalIOTerm),
currentLoanAge(currentLoanAge),
grossCoupon(grossCoupon),
feeStrip(feeStrip),
accrualBasis(accrualBasis),
paymentFrequency(paymentFrequency),
accrualStartDay(accrualStartDay)
{
currentLoanAge = Utilities::DateTime::monthsBetween(firstPaymentDate, factorDate);
netCoupon = grossCoupon - feeStrip;
if (periodicAmortizingDebtService)
{
Expand Down
3 changes: 2 additions & 1 deletion src/engine/loan.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Loan
std::string id;
double originalBalance;
double currentBalance;
struct tm firstPaymentDate;
struct tm factorDate;
int originalLoanTerm;
int originalAmortTerm;
Expand All @@ -36,11 +37,11 @@ class Loan
Loan(std::string id,
double originalBalance,
double currentBalance,
struct tm firstPaymentDate,
struct tm factorDate,
int originalLoanTerm,
int originalAmortTerm,
int originalIOTerm,
int currentLoanAge,
double grossCoupon,
double feeStrip,
AccrualBasis accrualBasis,
Expand Down
73 changes: 73 additions & 0 deletions src/engine/utilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#include <cmath>
#include <ctime>
#include <iostream>
#include <iomanip>

#include "constants.h"

namespace Utilities
{

double changeCompoundingBasis(
double rate, int origCompoundsPerYear, int newCompoundsPerYear)
{
return 1.0 - pow(1.0 - rate, float(origCompoundsPerYear) / float(newCompoundsPerYear));
}

double calculatePayment(double balance, int amortTerm, double periodicRate)
{
if (amortTerm == 0)
{
return periodicRate * balance;
}
else
{
return balance * periodicRate / (1 - pow(1 + periodicRate, -amortTerm));
}
}

namespace DateTime
{
struct tm createTime(int year, int month, int day)
{
struct tm date;
date.tm_hour = 0;
date.tm_min = 0;
date.tm_sec = 0;
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
return date;
}

struct tm addDateInterval(struct tm date, int years, int months, int days)
{
date.tm_year += years;
date.tm_mon += months;
date.tm_mday += days;
mktime(&date);
return date;
}

int toYYYYMMDD(struct tm date)
{
char date_YYYYMMDD[9];
strftime(date_YYYYMMDD, 9, "%Y%m%d", &date);
return std::stoi(date_YYYYMMDD);
}

int daysBetween(struct tm date1, struct tm date2, bool inclusiveEnd = true)
{
int secondsBetween = std::difftime(mktime(&date2), mktime(&date1));
return int(secondsBetween / 60.0 / 60.0 / 24.0) + (inclusiveEnd ? 1 : 0);
}

int monthsBetween(struct tm date1, struct tm date2)
{
// Ignores the day of month
return (date2.tm_year - date1.tm_year) * 12 + date2.tm_mon - date1.tm_mon;
}

} // namespace DateTime

} // namespace Utilities
59 changes: 11 additions & 48 deletions src/engine/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,24 @@
namespace Utilities
{

inline double changeCompoundingBasis(
double rate, int origCompoundsPerYear, int newCompoundsPerYear)
{
return 1.0 - pow(1.0 - rate, float(origCompoundsPerYear) / float(newCompoundsPerYear));
}
double changeCompoundingBasis(double rate, int origCompoundsPerYear, int newCompoundsPerYear);

inline double calculatePayment(double balance, int amortTerm, double periodicRate)
{
if (amortTerm == 0)
{
return periodicRate * balance;
}
else
double calculatePayment(double balance, int amortTerm, double periodicRate);

namespace DateTime
{
return balance * periodicRate / (1 - pow(1 + periodicRate, -amortTerm));
}
}

struct tm createTime(int year, int month, int day);

namespace DateTime
{
inline struct tm createTime(int year, int month, int day)
{
struct tm date;
date.tm_hour = 0;
date.tm_min = 0;
date.tm_sec = 0;
date.tm_year = year - 1900;
date.tm_mon = month - 1;
date.tm_mday = day;
return date;
}
struct tm addDateInterval(struct tm date, int years, int months, int days);

inline struct tm addDateInterval(struct tm date, int years, int months, int days)
{
date.tm_year += years;
date.tm_mon += months;
date.tm_mday += days;
mktime(&date);
return date;
}
int toYYYYMMDD(struct tm date);

inline int toYYYYMMDD(struct tm date)
{
char date_YYYYMMDD[9];
strftime(date_YYYYMMDD, 9, "%Y%m%d", &date);
return std::stoi(date_YYYYMMDD);
}
int daysBetween(struct tm date1, struct tm date2, bool inclusiveEnd = true);

inline int daysBetween(struct tm date1, struct tm date2, bool inclusiveEnd = true)
{
int secondsBetween = std::difftime(mktime(&date2), mktime(&date1));
return int(secondsBetween / 60.0 / 60.0 / 24.0) + (inclusiveEnd ? 1 : 0);
}
} // namespace DateTime
int monthsBetween(struct tm date1, struct tm date2);

} // namespace DateTime

} // namespace Utilities

Expand Down
2 changes: 1 addition & 1 deletion src/frontend/DataLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ public override Deal LoadDeal(string dealName)
loanId: "1717469130",
originalBalance: 763000.0,
currentBalance: 763000.0,
firstPaymentDate: new DateTime(2019, 2, 1).AddMonths(-i),
factorDate: new DateTime(2019, 2, 1),
originalLoanTerm: 60,
originalAmortTerm: 360,
originalIOTerm: 0,
currentLoanAge: i,
grossCoupon: 0.0496,
feeStrip: 0.0248,
accrualBasis: AccrualBasis.ACTUAL_360,
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/Loan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ public enum AccrualBasis
public sealed class Loan : IPrettyPrintable
{
[DllImport("../../bin/mbs_analytics", CharSet = CharSet.Ansi)]
private static extern IntPtr CreateLoan([MarshalAs(UnmanagedType.LPStr)] string loanId, double originalBalance, double currentBalance, StructDateTime factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, int currentLoanAge, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, string originalPrepaymentString);
private static extern IntPtr CreateLoan([MarshalAs(UnmanagedType.LPStr)] string loanId, double originalBalance, double currentBalance, StructDateTime firstPaymentDate, StructDateTime factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, string originalPrepaymentString);
[DllImport("../../bin/mbs_analytics")]
private static extern void DeleteLoan(IntPtr loan);
[DllImport("../../bin/mbs_analytics")]
private static extern IntPtr PrettyDescriptionLoan(IntPtr loan);
private IntPtr loan;
public static implicit operator IntPtr(Loan loan) => loan.loan;

public Loan(string loanId, double originalBalance, double currentBalance, DateTime factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, int currentLoanAge, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, string originalPrepaymentString)
public Loan(string loanId, double originalBalance, double currentBalance, DateTime firstPaymentDate, DateTime factorDate, int originalLoanTerm, int originalAmortTerm, int originalIOTerm, double grossCoupon, double feeStrip, AccrualBasis accrualBasis, string originalPrepaymentString)
{
loan = CreateLoan(loanId, originalBalance, currentBalance, factorDate, originalLoanTerm, originalAmortTerm, originalIOTerm, currentLoanAge, grossCoupon, feeStrip, accrualBasis, originalPrepaymentString);
loan = CreateLoan(loanId, originalBalance, currentBalance, firstPaymentDate, factorDate, originalLoanTerm, originalAmortTerm, originalIOTerm, grossCoupon, feeStrip, accrualBasis, originalPrepaymentString);
}


Expand Down
31 changes: 31 additions & 0 deletions test/engine/test_utilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "catch.hpp"
#include "utilities.h"

using namespace Utilities::DateTime;

TEST_CASE("Check date difference in months matches expected value")
{
auto date1 = createTime(2019, 1, 1);
auto date2 = createTime(2019, 9, 1);
auto date3 = createTime(2020, 3, 1);

REQUIRE(monthsBetween(date1, date1) == 0);
REQUIRE(monthsBetween(date1, date2) == 8);
REQUIRE(monthsBetween(date1, date3) == 14);
REQUIRE(monthsBetween(date2, date3) == 6);
REQUIRE(monthsBetween(date2, date1) == -8);
REQUIRE(monthsBetween(date3, date1) == -14);
REQUIRE(monthsBetween(date3, date2) == -6);
}

TEST_CASE("Check date difference in days matches expected value")
{
auto date1 = createTime(2019, 1, 1);
auto date2 = createTime(2019, 3, 1);
auto date3 = createTime(2031, 6, 1);

REQUIRE(daysBetween(date1, date1, false) == 0);
REQUIRE(daysBetween(date1, date2, false) == 59);
REQUIRE(daysBetween(date1, date2, true) == 60);
REQUIRE(daysBetween(date1, date3, false) == 4534);
}

0 comments on commit 3849f6c

Please sign in to comment.