일자를 입력받아서 일수 산출을 추가.
import java.math.BigDecimal;
import java.util.Calendar;
public class NewtonRaphson11 {
/**
* @param args
*
* cashArray : 투자금액과 회수금액(투자금액은 마이너스로 입력)
* dateArray : 현금흐름의 날짜.
*
* daysArray3 = new double[]{0,0,0,0,0,0,0,0,0,0};
* daysArray3 는 n-1 개의 값으로 초기화한다.(n= cashArray 또는 dateArray의 갯수)
*
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
double cashArray[] = null;
//double estimate = 0;
double daysArray1[] = null;
double daysArray2[] = null;
double daysArray3[] = null;
double daysArray4[] = null;
double result = 0;
//estimate = 0.909;
BigDecimal estimate = new BigDecimal("0.00909"); // 1/(1+0.1) = 0.909 엑셀함수 XIRR에서의 Default 0.1
System.out.println("===============================");
//A사 XIRR
BigDecimal[] cashArray3 = { new BigDecimal("-7499991600")
,new BigDecimal("138888750" )
,new BigDecimal("1404232862" )
,new BigDecimal("770860394" )
,new BigDecimal("-10930100" )
,new BigDecimal("2776693282" )
,new BigDecimal("-13953230" )
,new BigDecimal("5412800000" )
,new BigDecimal("-27200000" )
,new BigDecimal("560669570" )
,new BigDecimal("-2817430" )};
String[] dateArray3 = { new String("20060424")
,new String("20070416")
,new String("20070510")
,new String("20070518")
,new String("20070522")
,new String("20070615")
,new String("20070619")
,new String("20070625")
,new String("20070627")
,new String("20070705")
,new String("20070709")};
daysArray3 = new double[10];
setDays(dateArray3, daysArray3);
//daysArray3 = new double[] {357,381,389,393,417,421,427,429,437,441};
result = 0;
result = getXIRR(cashArray3, daysArray3, estimate);
result = Math.round(result * 10000);
result = result / 100;
System.out.println("A사 XIRR :" + result + "%");
//B사 XIRR
BigDecimal[] cashArray2 = { new BigDecimal("-5625000000")
,new BigDecimal("125000000" )
,new BigDecimal("3657370000" )
,new BigDecimal("7792000000" )};
String[] dateArray2 = { new String("20051229")
,new String("20070420")
,new String("20070801")
,new String("20070814")};
daysArray2 = new double[3];
setDays(dateArray2, daysArray2);
//daysArray2 = new double[] {477,580,593};
result = 0;
result = getXIRR(cashArray2, daysArray2, estimate);
result = Math.round(result * 10000);
result = result / 100;
System.out.println("B사 XIRR :" + result + "%");
//C 사 XIRR
BigDecimal[] cashArray1 = { new BigDecimal("-5355350000")
,new BigDecimal("7210700000" )
,new BigDecimal("-26776740" )};
String[] dateArray1 = { new String("20051229")
,new String("20070912")
,new String("20070914")};
daysArray1 = new double[2];
setDays(dateArray1, daysArray1);
//daysArray1 = new double[] {622,624};
result = getXIRR(cashArray1, daysArray1, estimate);
result = Math.round(result * 10000);
result = result / 100;
System.out.println("C사 XIRR :" + result + "%");
System.out.println("===============================");
}
/**
* @param dateArray : 현금흐름 일자들
* daysArray : 산출된일수
*
*/
static public void setDays(String dateArray[], double daysArray[]) {
int i = 0;
double cnt = 0;
if (dateArray != null && dateArray.length > 0) {
for(i = 1 ; i < dateArray.length; i++) {
cnt = calDays(dateArray[0], dateArray[i]);
daysArray[i-1] = cnt - 1;
}
}
}
/**
* @param date1 : from date
* date2 : to date
*
* 일수계산하기
*/
static public double calDays(String date1, String date2) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.set(Integer.parseInt(date1.substring(0,4)), Integer.parseInt(date1.substring(4,6)), Integer.parseInt(date1.substring(6,8)));
cal2.set(Integer.parseInt(date2.substring(0,4)), Integer.parseInt(date2.substring(4,6)), Integer.parseInt(date2.substring(6,8)));
double cnt = 0;
while (!cal1.after(cal2)) {
cnt++;
cal1.add(Calendar.DATE, 1);
}
return cnt;
}
/**
* Newton-Raphson Method
*
*
* f(XIRR) = cashFlows[0] + cashFlows[1]/(1+XIRR)^(days[0]/365) + cashFlows[2]/(1+XIRR)^(days[1]/365)
+ cashFlows[3]/(1+XIRR)^(days[2]/365) + cashFlows[4]/(1+XIRR)^(days[3]/365) ....
*
* X = 1/(1+XIRR) change..
*
* f(X) = cashFlows[0] + cashFlows[1]*X^(days[0]/365) + cashFlows[2]*X^(days[1]/365) + cashFlows[3]/*X^(days[2]/365)
+ cashFlows[4]/*X^(days[3]/365) ....
*
* f'(X) = (days[0]/365)*cashFlows[1] + (days[1]/365)*cashFlows[2]*X^(days[1]/365) + (days[2]/365)*cashFlows[3]/*X^(days[2]/365)
+ (days[3]/365)*cashFlows[4]/*X^(days[3]/365) ....
*
* X2 = X1 - f(X1)/f'(X1)
* X3 = X2 - f(X2)/f'(X2)
* .
* .
*
* 2007-08-30
* / hwan0112@hanmail.net / racle4.tistory.com
*
*/
static public double getXIRR(final BigDecimal[] cashFlows, final double[] daysArray, final BigDecimal estimatedResult) {
//double result = Double.NaN;
double result = 0;
BigDecimal fx = new BigDecimal("0");
BigDecimal fp = new BigDecimal("0");
//BigDecimal x1 = new BigDecimal("1");
//BigDecimal x2 = new BigDecimal("0");
//BigDecimal days = new BigDecimal("0");
//double fx = 0;
//double fp = 0;
double x1 = 1;
double x2 = 0;
double days = 0;
int i = 0;
int j = 0;
final int maxIteration = 100;
if (cashFlows != null && cashFlows.length > 0) {
if (!cashFlows[0].equals("0")) {
if (!estimatedResult.equals("")) {
x1 = estimatedResult.doubleValue();
//if (x1.getValue() <= 0.0) x1 = 0.5;
}
//System.out.println("x fx fp x2" );
//System.out.println("S ==================================================");
for(i = 1 ; i < maxIteration; i++) {
fx = new BigDecimal("0");
fp = new BigDecimal("0");
fx = cashFlows[0];
for (j = 1; j < cashFlows.length; j++) {
days = daysArray[j-1]/365;
fx = fx.add(cashFlows[j].multiply(new BigDecimal(Math.pow(x1, days))));
}// calculate fx
for (j = 1; j < cashFlows.length; j++) {
days = daysArray[j-1]/365;
fp = fp.add(cashFlows[j].multiply(new BigDecimal(days * Math.pow(x1, days-1))));
}// calculate fp
/*
x2 = x1 - fx/fp;
*/
fx = fx.divide(fp, 1);
x2 = x1 - fx.doubleValue();
//System.out.println(x1 + " " + fx+ " " + fp+ " " + x2 );
if(Math.abs(x1 - x2) < 0.00001){
result = 1/x2 - 1;
break;
}
x1 = x2;
}
}
}
return result;
}
}
결과
===============================
A사 XIRR :40.1%
B사 XIRR :56.56%
C사 XIRR :18.81%
===============================
** 엑셀함수 이용한 결과값과 비교.
-------------------------------------------------------------------------------------------------
ps. 최소 할인율 0%, 최대할인율 = 이율 인 채권의 할인율 산정시에는 Newton-Raphson Method 보다는
Bisection Method를 권장한다.