I have made this function that should take a set of price data and calculate a set of monthly returns. The idea is that is should be able to cope with irregular time intervals.For example I have daily data for the S&P 500 but many hedge funds only release price data monthly.Here is what I have come up with://Turns a price series into an array of monthly returns. function monthlyReturns($dates, $prices, $startDate = , $endDate = ){if ($endDate == ) $endDate = time();if (count($dates) != count($prices)){die(The dates array must be the same length as the prices array);}  $i = 0; $firstPass = false;foreach ($dates as $date){  $d = strtotime($date);  if ($startDate ==  || ($d >= $startDate && $d <= $endDate )) :    $p = $prices[$i];    $month = date('M',$d);    $year = date('Y',$d);    if ($i == 0 || $firstPass == false){      $startPrice = $p;      $lastMonth = $month;    }    if ($month != $lastMonth && $i != 0){      $returnTable['date'][] = $dates[$i-1];      $returnTable['return'][] = $p / $startPrice - 1;      $startPrice = $p;    }    $lastMonth = $month;    $firstPass = true;  endif;  $i++;  }   return $returnTable;}I noticed that for a fund with only monthly data the returns are off by a month. Can anyone see any major flaws with this function that could explain this or a solution to solve it.For info, the monthly returns for hedge funds often come near the end of the month. E.g.date       | Price-----------------2013-01-29 | 25.692013-02-28 | 27.622013-03-30 | 26.532013-04-29 | 28.45
improvements to this php function to calculate monthly returns from a set of price data
php
If there are now performance constraint I always prefere a readable solution over a compact one. So I would go with the following: (assuming $prices is sorted and there are no gaps in the months)<?date_default_timezone_set('Europe/Berlin');//Put the data into a assoc array. If necessary I would maybe create a separate//method to create this input or put it also to extractMonthlyFinalPrice()$prices=array(); $prices['2013-01-29']='25.69';$prices['2013-02-28']='27.62';$prices['2013-03-02']='13.53';$prices['2013-03-07']='16.53';$prices['2013-03-30']='26.53';$prices['2013-03-30']='26.53';$prices['2013-04-29']='28.45';$monthlyFinalPrice=extractMonthlyFinalPrice($prices);/*array(4) {  [2013-01]=> string(5) 25.69  [2013-02]=> string(5) 27.62  [2013-03]=> string(5) 26.53  [2013-04]=> string(5) 28.45}*/$monthlyReturns=calculateMonthlyReturn($monthlyFinalPrice,new DateTime(2013-02));/*array(3) {  [2013-02]=>  float(1.93)  //with '2013-01' as start  [2013-03]=>  float(-1.09)  [2013-04]=>  float(1.92)*/function extractMonthlyFinalPrice($prices){    $monthlyPrice=array();    foreach ($prices as $date=>$price)    {        $month=substr($date,0,7);        $monthlyPrice[$month]=$price; // just overwrite existing value and use the last    }    return $monthlyPrice;}//Be careful with timestamps. Think about using DateTime.function calculateMonthlyReturn($monthlyFinalPrice, DateTime $startDate=null, DateTime $endDate=null){    if ($endDate==null) $endDate=new DateTime();    $monthlyReturns=array();    $lastMonthPrice=null;    foreach ($monthlyFinalPrice as $month=>$price)    {        $date=new DateTime($month);        $inRange = $date>=$startDate && $date <=$endDate;        if ($lastMonthPrice!=null && $inRange)        {            $monthlyReturns[$month]=$price-$lastMonthPrice;        }            //assuming that there are no gaps in the list.             //Otherwise some date magic is required.        $lastMonthPrice=$price;     }    return $monthlyReturns;}As you see, there is no much logic left. I get rid of a bunch of ifs and could split the bigger problem in two smaller own. Now you could write tests independently.