package name.abuchen.portfolio.snapshot;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.hamcrest.number.IsCloseTo;
import org.junit.Test;
import name.abuchen.portfolio.AccountBuilder;
import name.abuchen.portfolio.PortfolioBuilder;
import name.abuchen.portfolio.SecurityBuilder;
import name.abuchen.portfolio.TaxonomyBuilder;
import name.abuchen.portfolio.TestCurrencyConverter;
import name.abuchen.portfolio.model.Account;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.Classification;
import name.abuchen.portfolio.model.Classification.Assignment;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Portfolio;
import name.abuchen.portfolio.model.PortfolioTransaction;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.model.Taxonomy;
import name.abuchen.portfolio.model.Transaction.Unit;
import name.abuchen.portfolio.money.CurrencyConverter;
import name.abuchen.portfolio.money.CurrencyUnit;
import name.abuchen.portfolio.money.Money;
import name.abuchen.portfolio.money.Values;
@SuppressWarnings("nls")
public class ClassificationIndexTest
{
private ReportingPeriod.FromXtoY period = new ReportingPeriod.FromXtoY( //
LocalDate.parse("2011-12-31"), LocalDate.parse("2012-01-08"));
private Client createClient(int weight)
{
Client client = new Client();
Taxonomy taxonomy = new TaxonomyBuilder() //
.addClassification("one") //
.addTo(client);
Security security = new SecurityBuilder() //
.addPrice("2011-12-31", 100 * Values.Quote.factor()) //
.addPrice("2012-01-03", 106 * Values.Quote.factor()) //
.addPrice("2012-01-08", 112 * Values.Quote.factor()) //
.assign(taxonomy, "one", weight) //
.addTo(client);
Account account = new AccountBuilder() //
.deposit_("2011-12-31", 10000 * Values.Amount.factor()) //
.interest("2012-01-01", 230 * Values.Amount.factor()) //
.deposit_("2012-01-02", 200 * Values.Amount.factor()) //
.interest("2012-01-02", 200 * Values.Amount.factor()) //
.withdraw("2012-01-03", 400 * Values.Amount.factor()) //
.fees____("2012-01-03", 234 * Values.Amount.factor()) //
.interest("2012-01-04", 293 * Values.Amount.factor()) //
.interest("2012-01-05", 293 * Values.Amount.factor()) //
.deposit_("2012-01-06", 5400 * Values.Amount.factor()) //
.interest("2012-01-06", 195 * Values.Amount.factor()) //
.withdraw("2012-01-07", 3697 * Values.Amount.factor()) //
.fees____("2012-01-07", 882 * Values.Amount.factor()) //
.fees____("2012-01-08", 1003 * Values.Amount.factor()) //
.dividend("2012-01-08", 100 * Values.Amount.factor(), security) //
.assign(taxonomy, "one", weight) //
.addTo(client);
new PortfolioBuilder(account) //
.buy(security, "2012-01-01", 50 * Values.Share.factor(), 50 * 101 * Values.Amount.factor()) //
.inbound_delivery(security, "2012-01-01", 100 * Values.Share.factor(),
100 * 100 * Values.Amount.factor()) //
.sell(security, "2012-01-05", 50 * Values.Share.factor(), 50 * 105 * Values.Amount.factor()) //
.addTo(client);
return client;
}
@Test
public void testThat100PercentAssignmentIsIdenticalToClientPerformance()
{
Client client = createClient(Classification.ONE_HUNDRED_PERCENT);
Classification classification = client.getTaxonomies().get(0).getClassificationById("one");
List<Exception> warnings = new ArrayList<Exception>();
CurrencyConverter converter = new TestCurrencyConverter();
PerformanceIndex iClient = PerformanceIndex.forClient(client, converter, period, warnings);
PerformanceIndex iClassification = PerformanceIndex.forClassification(client, converter, classification, period,
warnings);
assertThat(warnings.isEmpty(), is(true));
assertThat(iClient.getDates(), is(iClassification.getDates()));
assertThat(iClient.getAccumulatedPercentage(), is(iClassification.getAccumulatedPercentage()));
assertThat(iClient.getDeltaPercentage(), is(iClassification.getDeltaPercentage()));
assertThat(iClient.getTotals(), is(iClassification.getTotals()));
assertThat(iClient.getTransferals(), is(iClassification.getTransferals()));
}
@Test
public void testThatPartialAssignmentIsNOTIdenticalToClientPerformance()
{
Client client = createClient(Classification.ONE_HUNDRED_PERCENT);
Classification classification = client.getTaxonomies().get(0).getClassificationById("one");
// remove account assignment
classification.getAssignments().remove(1);
List<Exception> warnings = new ArrayList<Exception>();
CurrencyConverter converter = new TestCurrencyConverter();
PerformanceIndex iClient = PerformanceIndex.forClient(client, converter, period, warnings);
PerformanceIndex iClassification = PerformanceIndex.forClassification(client, converter, classification, period,
warnings);
assertThat(warnings.isEmpty(), is(true));
assertThat(iClient.getAccumulatedPercentage(), is(not(iClassification.getAccumulatedPercentage())));
assertThat(iClient.getDeltaPercentage(), is(not(iClassification.getDeltaPercentage())));
assertThat(iClient.getTotals(), is(not(iClassification.getTotals())));
assertThat(iClient.getTransferals(), is(not(iClassification.getTransferals())));
}
@Test
public void testThat50PercentAssignmentHasIdenticalPerformanceButOnly50PercentTotals()
{
Client client = createClient(Classification.ONE_HUNDRED_PERCENT / 2);
Classification classification = client.getTaxonomies().get(0).getClassificationById("one");
List<Exception> warnings = new ArrayList<Exception>();
CurrencyConverter converter = new TestCurrencyConverter();
PerformanceIndex iClient = PerformanceIndex.forClient(client, converter, period, warnings);
PerformanceIndex iClassification = PerformanceIndex.forClassification(client, converter, classification, period,
warnings);
assertThat(warnings.isEmpty(), is(true));
assertThat(iClient.getDates(), is(iClassification.getDates()));
assertThat(iClient.getAccumulatedPercentage(), is(iClassification.getAccumulatedPercentage()));
assertThat(iClient.getDeltaPercentage(), is(iClassification.getDeltaPercentage()));
assertThat(half(iClient.getTotals()), is(iClassification.getTotals()));
assertThat(half(iClient.getTransferals()), is(iClassification.getTransferals()));
}
private long[] half(long[] transferals)
{
long[] answer = new long[transferals.length];
for (int ii = 0; ii < transferals.length; ii++)
answer[ii] = transferals[ii] / 2;
return answer;
}
@Test
public void testThatTaxesAreNotIncludedInTTWRORCalculation()
{
Client client = new Client();
Security security = new SecurityBuilder() //
.addPrice("2015-12-31", Values.Quote.factorize(100)) //
.addPrice("2016-12-31", Values.Quote.factorize(110)) //
.addTo(client);
Account account = new AccountBuilder() //
.addTo(client);
AccountTransaction t = new AccountTransaction();
t.setType(AccountTransaction.Type.DIVIDENDS);
t.setDate(LocalDate.parse("2016-06-01"));
t.setSecurity(security);
t.setMonetaryAmount(Money.of(CurrencyUnit.EUR, Values.Amount.factorize(100)));
t.setShares(Values.Share.factorize(10));
account.addTransaction(t);
Portfolio portfolio = new PortfolioBuilder(account) //
.addTo(client);
portfolio.addTransaction(new PortfolioTransaction("2015-12-31", //
CurrencyUnit.EUR, Values.Amount.factorize(1000), //
security, Values.Share.factorize(10), PortfolioTransaction.Type.BUY, //
0, 0));
portfolio.addTransaction(new PortfolioTransaction("2016-12-31", //
CurrencyUnit.EUR, Values.Amount.factorize(1070), //
security, Values.Share.factorize(10), PortfolioTransaction.Type.SELL, //
0, Values.Amount.factorize(30)));
Classification classification = new Classification(null, null);
classification.addAssignment(new Assignment(security));
List<Exception> warnings = new ArrayList<Exception>();
PerformanceIndex index = PerformanceIndex.forClassification(client, new TestCurrencyConverter(), classification,
new ReportingPeriod.FromXtoY(LocalDate.parse("2015-01-01"), LocalDate.parse("2017-01-01")),
warnings);
assertThat(warnings.isEmpty(), is(true));
// dividend payment 10% * quote change 10%
assertThat(index.getFinalAccumulatedPercentage(), IsCloseTo.closeTo((1.1 * 1.1) - 1, 0.000000001d));
// add taxes to dividend payment
t.addUnit(new Unit(Unit.Type.TAX, Money.of(CurrencyUnit.EUR, Values.Amount.factorize(50))));
index = PerformanceIndex.forClassification(client, new TestCurrencyConverter(), classification,
new ReportingPeriod.FromXtoY(LocalDate.parse("2015-01-01"), LocalDate.parse("2017-01-01")),
warnings);
// dividend payment 15% * quote change 10%
assertThat(index.getFinalAccumulatedPercentage(), IsCloseTo.closeTo((1.15 * 1.1) - 1, 0.000000001d));
}
}