My formula example does not include cash dividend, management fees (ie. SPY), holding taxes.
Daily %=(px[i]-px[i-1])/px[i-1], where px[i] today and px[i-1] is yesterday.
Annual %=(daily[Jan 1st]+1)*(daily[Jan 2nd]+1)....about 252 days terms)-1.
In Java, you could use this function. Pass in a daily time-series of returns.
public static List<Tuple2<LocalDate,Double>> calcAnnualReturns(List<LocalDate> date, List<Double> values) {
List<Tuple2<LocalDate,Double>> list = new ArrayList<>();
int lastYear=-1;
BigDecimal tally=BigDecimal.ZERO;
if( values.size()>0 ) {
for (int i = 0; i < values.size(); i++) {
LocalDate ldt=date.get(i);
double value=values.get(i);
if( i==0 ) {
tally=BigDecimal.valueOf(value+1);
}else{
if( ldt.getYear()>lastYear ) {
// calculate
tally=tally.subtract(BigDecimal.ONE);
// add result
list.add(new Tuple2(LocalDate.of(lastYear, 12, 31), tally.doubleValue()));
// reset to new year
tally=BigDecimal.valueOf(value+1);
}else{
tally=tally.multiply(BigDecimal.valueOf(value+1));
}
}
//
lastYear=ldt.getYear();
}
// finish last value
tally=tally.subtract(BigDecimal.ONE);
list.add(new Tuple2(LocalDate.of(lastYear, 12, 31), tally.doubleValue()));
}
return list;
}