@@ -2148,7 +2148,7 @@ public static function TBILLPRICE($settlement, $maturity, $discount)
21482148     *                                The maturity date is the date when the Treasury bill expires. 
21492149     * @param int $price The Treasury bill's price per $100 face value 
21502150     * 
2151-      * @return float 
2151+      * @return float|mixed|string  
21522152     */ 
21532153    public  static  function  TBILLYIELD ($ settlement , $ maturity , $ price )
21542154    {
@@ -2183,6 +2183,23 @@ public static function TBILLYIELD($settlement, $maturity, $price)
21832183        return  Functions::VALUE ();
21842184    }
21852185
2186+     /** 
2187+      * XIRR. 
2188+      * 
2189+      * Returns the internal rate of return for a schedule of cash flows that is not necessarily periodic. 
2190+      * 
2191+      * Excel Function: 
2192+      *        =XIRR(values,dates,guess) 
2193+      * 
2194+      * @param float[] $values     A series of cash flow payments 
2195+      *                                The series of values must contain at least one positive value & one negative value 
2196+      * @param mixed[] $dates      A series of payment dates 
2197+      *                                The first payment date indicates the beginning of the schedule of payments 
2198+      *                                All other dates must be later than this date, but they may occur in any order 
2199+      * @param float $guess        An optional guess at the expected answer 
2200+      * 
2201+      * @return float|mixed|string 
2202+      */ 
21862203    public  static  function  XIRR ($ values , $ dates , $ guess  = 0.1 )
21872204    {
21882205        if  ((!is_array ($ values )) && (!is_array ($ dates ))) {
@@ -2195,11 +2212,28 @@ public static function XIRR($values, $dates, $guess = 0.1)
21952212            return  Functions::NAN ();
21962213        }
21972214
2215+         $ datesCount  = count ($ dates );
2216+         for  ($ i  = 0 ; $ i  < $ datesCount ; ++$ i ) {
2217+             $ dates [$ i ] = DateTime::getDateValue ($ dates [$ i ]);
2218+             if  (!is_numeric ($ dates [$ i ])) {
2219+                 return  Functions::VALUE ();
2220+             }
2221+         }
2222+         if  (min ($ dates ) != $ dates [0 ]) {
2223+             return  Functions::NAN ();
2224+         }
2225+ 
21982226        // create an initial range, with a root somewhere between 0 and guess 
21992227        $ x1  = 0.0 ;
22002228        $ x2  = $ guess ;
22012229        $ f1  = self ::XNPV ($ x1 , $ values , $ dates );
2230+         if  (!is_numeric ($ f1 )) {
2231+             return  $ f1 ;
2232+         }
22022233        $ f2  = self ::XNPV ($ x2 , $ values , $ dates );
2234+         if  (!is_numeric ($ f2 )) {
2235+             return  $ f2 ;
2236+         }
22032237        for  ($ i  = 0 ; $ i  < self ::FINANCIAL_MAX_ITERATIONS ; ++$ i ) {
22042238            if  (($ f1  * $ f2 ) < 0.0 ) {
22052239                break ;
@@ -2210,7 +2244,7 @@ public static function XIRR($values, $dates, $guess = 0.1)
22102244            }
22112245        }
22122246        if  (($ f1  * $ f2 ) > 0.0 ) {
2213-             return  Functions::VALUE ();
2247+             return  Functions::NAN ();
22142248        }
22152249
22162250        $ f  = self ::XNPV ($ x1 , $ values , $ dates );
@@ -2247,15 +2281,15 @@ public static function XIRR($values, $dates, $guess = 0.1)
22472281     *        =XNPV(rate,values,dates) 
22482282     * 
22492283     * @param float $rate the discount rate to apply to the cash flows 
2250-      * @param array of  float     $values     A series of cash flows that corresponds to a schedule of payments in dates. 
2284+      * @param float[]  $values     A series of cash flows that corresponds to a schedule of payments in dates. 
22512285     *                                         The first payment is optional and corresponds to a cost or payment that occurs at the beginning of the investment. 
22522286     *                                         If the first value is a cost or payment, it must be a negative value. All succeeding payments are discounted based on a 365-day year. 
22532287     *                                         The series of values must contain at least one positive value and one negative value. 
2254-      * @param array of  mixed     $dates      A schedule of payment dates that corresponds to the cash flow payments. 
2288+      * @param mixed[]  $dates      A schedule of payment dates that corresponds to the cash flow payments. 
22552289     *                                         The first payment date indicates the beginning of the schedule of payments. 
22562290     *                                         All other dates must be later than this date, but they may occur in any order. 
22572291     * 
2258-      * @return float 
2292+      * @return float|mixed|string  
22592293     */ 
22602294    public  static  function  XNPV ($ rate , $ values , $ dates )
22612295    {
@@ -2273,7 +2307,7 @@ public static function XNPV($rate, $values, $dates)
22732307            return  Functions::NAN ();
22742308        }
22752309        if  ((min ($ values ) > 0 ) || (max ($ values ) < 0 )) {
2276-             return  Functions::VALUE ();
2310+             return  Functions::NAN ();
22772311        }
22782312
22792313        $ xnpv  = 0.0 ;
0 commit comments