package name.abuchen.portfolio.snapshot.security;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import name.abuchen.portfolio.math.IRR;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.PortfolioTransaction;
import name.abuchen.portfolio.model.Transaction.Unit;
import name.abuchen.portfolio.money.CurrencyConverter;
import name.abuchen.portfolio.money.Values;
/* package */class IRRCalculation extends Calculation
{
private List<LocalDate> dates = new ArrayList<>();
private List<Double> values = new ArrayList<>();
@Override
public void visit(CurrencyConverter converter, DividendInitialTransaction t)
{
dates.add(t.getDate());
values.add(-t.getMonetaryAmount().with(converter.at(t.getDate())).getAmount() / Values.Amount.divider());
}
@Override
public void visit(CurrencyConverter converter, DividendFinalTransaction t)
{
dates.add(t.getDate());
values.add(t.getMonetaryAmount().with(converter.at(t.getDate())).getAmount() / Values.Amount.divider());
}
@Override
public void visit(CurrencyConverter converter, DividendTransaction t)
{
dates.add(t.getDate());
long taxes = t.getUnitSum(Unit.Type.TAX, converter).getAmount();
long amount = t.getMonetaryAmount().with(converter.at(t.getDate())).getAmount();
values.add((amount + taxes) / Values.Amount.divider());
}
@Override
public void visit(CurrencyConverter converter, AccountTransaction t)
{
// ignore tax refunds when calculating the irr for a single security
}
@Override
public void visit(CurrencyConverter converter, PortfolioTransaction t)
{
dates.add(t.getDate());
long taxes = t.getUnitSum(Unit.Type.TAX, converter).getAmount();
long amount = t.getMonetaryAmount(converter).getAmount();
switch (t.getType())
{
case BUY:
case DELIVERY_INBOUND:
case TRANSFER_IN:
values.add((-amount + taxes) / Values.Amount.divider());
break;
case SELL:
case DELIVERY_OUTBOUND:
case TRANSFER_OUT:
values.add((amount + taxes) / Values.Amount.divider());
break;
default:
throw new UnsupportedOperationException();
}
}
public double getIRR()
{
// see #457: if the reporting period contains only tax refunds, dates
// (and values) can be empty and no IRR can be calculated
if (dates.isEmpty())
return Double.NaN;
return IRR.calculate(dates, values);
}
}