본문 바로가기

Etc.

XIRR 자바버전2

일자를 입력받아서 일수 산출을 추가.

 

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를 권장한다.