package name.abuchen.portfolio.snapshot.security;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import name.abuchen.portfolio.model.Account;
import name.abuchen.portfolio.model.AccountTransaction;
import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Portfolio;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.money.CurrencyConverter;
import name.abuchen.portfolio.snapshot.PortfolioSnapshot;
import name.abuchen.portfolio.snapshot.ReportingPeriod;
import name.abuchen.portfolio.snapshot.SecurityPosition;
import name.abuchen.portfolio.snapshot.filter.PortfolioClientFilter;
public class SecurityPerformanceSnapshot
{
public static SecurityPerformanceSnapshot create(Client client, CurrencyConverter converter, ReportingPeriod period)
{
Map<Security, SecurityPerformanceRecord> transactions = initRecords(client);
for (Account account : client.getAccounts())
extractSecurityRelatedAccountTransactions(account, period, transactions);
for (Portfolio portfolio : client.getPortfolios())
{
extractSecurityRelatedPortfolioTransactions(portfolio, period, transactions);
addPseudoValuationTansactions(portfolio, converter, period, transactions);
}
return doCreateSnapshot(client, converter, transactions, period);
}
public static SecurityPerformanceSnapshot create(Client client, CurrencyConverter converter, Portfolio portfolio,
ReportingPeriod period)
{
return create(new PortfolioClientFilter(portfolio).filter(client), converter, period);
}
private static Map<Security, SecurityPerformanceRecord> initRecords(Client client)
{
Map<Security, SecurityPerformanceRecord> records = new HashMap<>();
for (Security s : client.getSecurities())
records.put(s, new SecurityPerformanceRecord(s));
return records;
}
private static SecurityPerformanceSnapshot doCreateSnapshot(Client client, CurrencyConverter converter,
Map<Security, SecurityPerformanceRecord> records, ReportingPeriod period)
{
List<SecurityPerformanceRecord> list = new ArrayList<>(records.values());
for (Iterator<SecurityPerformanceRecord> iter = list.iterator(); iter.hasNext();)
{
SecurityPerformanceRecord record = iter.next();
if (record.getTransactions().isEmpty())
{
// remove records that have no transactions
// during the reporting period
iter.remove();
}
else
{
// calculate values for each security
record.calculate(client, converter, period);
}
}
return new SecurityPerformanceSnapshot(list);
}
private static void extractSecurityRelatedAccountTransactions(Account account, ReportingPeriod period,
Map<Security, SecurityPerformanceRecord> records)
{
for (AccountTransaction t : account.getTransactions())
{
if (t.getSecurity() == null)
continue;
if (!period.containsTransaction().test(t))
continue;
if (t.getType() == AccountTransaction.Type.DIVIDENDS //
|| t.getType() == AccountTransaction.Type.INTEREST)
{
DividendTransaction dt = new DividendTransaction();
dt.setDate(t.getDate());
dt.setSecurity(t.getSecurity());
dt.setAccount(account);
dt.setCurrencyCode(t.getCurrencyCode());
dt.setAmount(t.getAmount());
dt.setShares(t.getShares());
dt.setNote(t.getNote());
dt.addUnits(t.getUnits());
records.get(t.getSecurity()).addTransaction(dt);
}
else if (t.getType() == AccountTransaction.Type.TAX_REFUND)
{
records.get(t.getSecurity()).addTransaction(t);
}
}
}
private static void extractSecurityRelatedPortfolioTransactions(Portfolio portfolio, ReportingPeriod period,
Map<Security, SecurityPerformanceRecord> records)
{
portfolio.getTransactions().stream() //
.filter(period.containsTransaction()) //
.forEach(t -> records.get(t.getSecurity()).addTransaction(t));
}
private static void addPseudoValuationTansactions(Portfolio portfolio, CurrencyConverter converter,
ReportingPeriod period, Map<Security, SecurityPerformanceRecord> records)
{
PortfolioSnapshot snapshot = PortfolioSnapshot.create(portfolio, converter, period.getStartDate());
for (SecurityPosition position : snapshot.getPositions())
{
records.get(position.getSecurity()).addTransaction(
new DividendInitialTransaction(position, period.getStartDate()));
}
snapshot = PortfolioSnapshot.create(portfolio, converter, period.getEndDate());
for (SecurityPosition position : snapshot.getPositions())
{
records.get(position.getSecurity()).addTransaction(
new DividendFinalTransaction(position, period.getEndDate()));
}
}
private List<SecurityPerformanceRecord> records;
private SecurityPerformanceSnapshot(List<SecurityPerformanceRecord> records)
{
this.records = records;
}
public List<SecurityPerformanceRecord> getRecords()
{
return records;
}
}