Skip to content

Commit

Permalink
Validate and replace recursion with iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
joutvhu committed Mar 31, 2023
1 parent c168d40 commit 2c9f68f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 29 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = 'com.github.joutvhu'
version = '1.0.0'
version = '1.0.1'

def snapshotVersion = version.endsWith('-SNAPSHOT') || version.endsWith('.SNAPSHOT')

Expand Down
70 changes: 46 additions & 24 deletions src/main/java/com/joutvhu/xirr/NewtonsXirr.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,50 +7,72 @@ class NewtonsXirr {
public NewtonsXirr(Transaction[] transactions) {
double[] payments = new double[transactions.length];
double[] days = new double[transactions.length];
boolean positive = false;
boolean negative = false;
for (int i = 0; i < payments.length; i++) {
Transaction transaction = transactions[i];
payments[i] = transaction.getAmount();
days[i] = transaction.getWhen();
if (payments[i] > 0)
positive = true;
if (payments[i] < 0)
negative = true;
}
validate(positive, negative);
this.f = fTotalXirr(payments, days);
this.df = dfTotalXirr(payments, days);
}

public NewtonsXirr(double[] payments, double[] days) {
if (payments.length != days.length) {
throw new XirrException("Payments and Days must have the same number of elements.");
}
boolean positive = false;
boolean negative = false;
for (double payment : payments) {
if (payment > 0)
positive = true;
if (payment < 0)
negative = true;
if (positive && negative)
break;
}
validate(positive, negative);
this.f = fTotalXirr(payments, days);
this.df = dfTotalXirr(payments, days);
}

private static XirrFx composeFunctions(XirrFx f1, XirrFx f2) {
return x -> f1.calculate(x) + f2.calculate(x);
}

private static XirrFx fXirr(double p, double dt, double dt0) {
return x -> p * Math.pow((1.0 + x), ((dt0 - dt) / 365.0));
}

private static XirrFx dfXirr(double p, double dt, double dt0) {
return x -> (1.0 / 365.0) * (dt0 - dt) * p * Math.pow((x + 1.0), (((dt0 - dt) / 365.0) - 1.0));
private static void validate(boolean positive, boolean negative) {
if (!positive && !negative) {
throw new XirrException("Expects at least one positive cash flow and one negative cash flow.");
}
if (!positive) {
throw new XirrException("Expects at least one positive cash flow.");
}
if (!negative) {
throw new XirrException("Expects at least one negative cash flow.");
}
}

public static XirrFx fTotalXirr(double[] payments, double[] days) {
XirrFx resf = x -> 0.0;

for (int i = 0; i < payments.length; i++) {
resf = composeFunctions(resf, fXirr(payments[i], days[i], days[0]));
}

return resf;
return x -> {
double rate = 0.0;
for (int i = 0; i < payments.length; i++) {
rate += payments[i] * Math.pow((1.0 + x), ((days[0] - days[i]) / 365.0));
}
return rate;
};
}

public static XirrFx dfTotalXirr(double[] payments, double[] days) {
XirrFx resf = x -> 0.0;

for (int i = 0; i < payments.length; i++) {
resf = composeFunctions(resf, dfXirr(payments[i], days[i], days[0]));
}

return resf;
return x -> {
double rate = 0.0;
for (int i = 0; i < payments.length; i++) {
rate += (1.0 / 365.0) * (days[0] - days[i]) *
payments[i] * Math.pow((x + 1.0), (((days[0] - days[i]) / 365.0) - 1.0));
}
return rate;
};
}

public double next(double x) {
Expand Down
10 changes: 6 additions & 4 deletions src/main/java/com/joutvhu/xirr/Xirr.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ public class Xirr {
private final double accurate;
private final double tries;

public Xirr() {
private Xirr() {
accurate = 0.000001;
tries = 100;
}
Expand Down Expand Up @@ -37,14 +37,16 @@ public double xirr(Transaction... transactions) {
return xirr(newtonsXirr, 0.1);
}

public double xirr(Transaction[] transactions, double guess) {
NewtonsXirr newtonsXirr = new NewtonsXirr(transactions);
return xirr(newtonsXirr, guess);
}

public double xirr(double[] payments, double[] days) {
return xirr(payments, days, 0.1);
}

public double xirr(double[] payments, double[] days, double guess) {
if (payments.length != days.length) {
throw new XirrException("Payments and Days must have the same number of elements.");
}
NewtonsXirr newtonsXirr = new NewtonsXirr(payments, days);
return xirr(newtonsXirr, guess);
}
Expand Down

0 comments on commit 2c9f68f

Please # to comment.