Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Statement of Assets : add total perf for TTWROR, TTWROR p.a. and IRR #4217

Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
import name.abuchen.portfolio.snapshot.AssetPosition;
import name.abuchen.portfolio.snapshot.ClientSnapshot;
import name.abuchen.portfolio.snapshot.GroupByTaxonomy;
import name.abuchen.portfolio.snapshot.PerformanceIndex;
import name.abuchen.portfolio.snapshot.ReportingPeriod;
import name.abuchen.portfolio.snapshot.SecurityPosition;
import name.abuchen.portfolio.snapshot.filter.ClientFilter;
Expand Down Expand Up @@ -242,17 +243,37 @@ private final List<Element> flatten(GroupByTaxonomy groupByTaxonomy)
return answer;
}

/* package */ final void calculatePerformanceAndInjectIntoElements(String currencyCode, Interval interval)
/* package */ final void calculatePerformanceAndInjectIntoElements(String currencyCode, Interval interval,
boolean calculateTotalsPerformance)
{
CacheKey key = new CacheKey(currencyCode, interval);

// already calculated?
if (calculated.contains(key))
return;

// do not compute the performance index per default
if (calculateTotalsPerformance)
{
List<Exception> warnings = new ArrayList<>();

// performance for sub totals (category) lines
elements.stream().filter(Element::isCategory)
.filter(e -> !Objects.equals(Classification.UNASSIGNED_ID,
e.getCategory().getClassification().getId()))
.forEach(e -> e.setPerformanceForCategoryTotals(
currencyCode, interval,
PerformanceIndex.forClassification(filteredClient, converter.with(currencyCode),
e.getCategory().getClassification(), interval, warnings)));
// performance for total lines
elements.stream().filter(Element::isGroupByTaxonomy)
.forEach(e -> e.setPerformanceForCategoryTotals(currencyCode, interval,
PerformanceIndex.forClient(filteredClient, converter.with(currencyCode),
interval, warnings)));
}
// performance for securities
var snapshot = LazySecurityPerformanceSnapshot.create(filteredClient, converter.with(currencyCode),
interval);

Map<Security, LazySecurityPerformanceRecord> map = snapshot.getRecords().stream()
.collect(Collectors.toMap(LazySecurityPerformanceRecord::getSecurity, r -> r));

Expand Down Expand Up @@ -605,7 +626,8 @@ private void addPerformanceColumns(List<ReportingPeriod> options)

Column column = new Column("ttwror", Messages.ColumnTTWROR, SWT.RIGHT, 80); //$NON-NLS-1$
labelProvider = new ReportingPeriodLabelProvider(
LazySecurityPerformanceRecord::getTrueTimeWeightedRateOfReturn);
LazySecurityPerformanceRecord::getTrueTimeWeightedRateOfReturn, true,
PerformanceIndex::getFinalAccumulatedPercentage);
column.setOptions(new ReportingPeriodColumnOptions(Messages.ColumnTTWROR_Option, options));
column.setGroupLabel(Messages.GroupLabelPerformance);
column.setDescription(Messages.LabelTTWROR);
Expand All @@ -616,7 +638,8 @@ private void addPerformanceColumns(List<ReportingPeriod> options)

column = new Column("ttwror_pa", Messages.ColumnTTWRORpa, SWT.RIGHT, 80); //$NON-NLS-1$
labelProvider = new ReportingPeriodLabelProvider(
LazySecurityPerformanceRecord::getTrueTimeWeightedRateOfReturnAnnualized);
LazySecurityPerformanceRecord::getTrueTimeWeightedRateOfReturnAnnualized, true,
PerformanceIndex::getFinalAccumulatedAnnualizedPercentage);
column.setOptions(new ReportingPeriodColumnOptions(Messages.ColumnTTWRORpa_Option, options));
column.setGroupLabel(Messages.GroupLabelPerformance);
column.setDescription(Messages.LabelTTWROR_Annualized);
Expand All @@ -626,7 +649,8 @@ private void addPerformanceColumns(List<ReportingPeriod> options)
support.addColumn(column);

column = new Column("irr", Messages.ColumnIRR, SWT.RIGHT, 80); //$NON-NLS-1$
labelProvider = new ReportingPeriodLabelProvider(LazySecurityPerformanceRecord::getIrr);
labelProvider = new ReportingPeriodLabelProvider(LazySecurityPerformanceRecord::getIrr, true,
PerformanceIndex::getPerformanceIRR);
column.setOptions(new ReportingPeriodColumnOptions(Messages.ColumnIRRPerformanceOption, options));
column.setMenuLabel(Messages.ColumnIRR_MenuLabel);
column.setGroupLabel(Messages.GroupLabelPerformance);
Expand Down Expand Up @@ -1050,6 +1074,7 @@ public static class Element implements Adaptable
private List<Element> children = new ArrayList<>();

private Map<CacheKey, LazySecurityPerformanceRecord> performance = new HashMap<>();
private Map<CacheKey, PerformanceIndex> performanceForCategoryTotals = new HashMap<>();

private Element(GroupByTaxonomy groupByTaxonomy, AssetCategory category, int sortOrder)
{
Expand Down Expand Up @@ -1115,6 +1140,16 @@ public LazySecurityPerformanceRecord getPerformance(String currencyCode, Interva
return performance.get(new CacheKey(currencyCode, period));
}

public void setPerformanceForCategoryTotals(String currencyCode, Interval period, PerformanceIndex index)
{
performanceForCategoryTotals.put(new CacheKey(currencyCode, period), index);
}

public PerformanceIndex getPerformanceForCategoryTotals(String currencyCode, Interval period)
{
return performanceForCategoryTotals.get(new CacheKey(currencyCode, period));
}

public boolean isGroupByTaxonomy()
{
return groupByTaxonomy != null && category == null && position == null;
Expand Down Expand Up @@ -1242,6 +1277,7 @@ public int compare(Object o1, Object o2)
{
private Function<LazySecurityPerformanceRecord, LazyValue<?>> valueProvider;
private Function<Stream<Object>, Object> collector;
private Function<PerformanceIndex, ?> valueProviderTotal;

public ElementValueProvider(Function<LazySecurityPerformanceRecord, LazyValue<?>> valueProvider,
Function<Stream<Object>, Object> collector)
Expand All @@ -1250,6 +1286,15 @@ public ElementValueProvider(Function<LazySecurityPerformanceRecord, LazyValue<?>
this.collector = collector;
}

public ElementValueProvider(Function<LazySecurityPerformanceRecord, LazyValue<?>> valueProvider,
Function<Stream<Object>, Object> collector,
Function<PerformanceIndex, ?> valueProviderTotal)
{
this.valueProvider = valueProvider;
this.collector = collector;
this.valueProviderTotal = valueProviderTotal;
}

public Object getValue(Element element, String currencyCode, Interval interval)
{
if (element.isSecurity())
Expand Down Expand Up @@ -1297,17 +1342,30 @@ public Object getValue(Element element, String currencyCode, Interval interval)
}
else if (element.isCategory())
{
if (collector == null)
if (collector == null && valueProviderTotal != null && !Objects.equals(Classification.UNASSIGNED_ID,
element.getCategory().getClassification().getId()))
{
// assumption: performance index has been calculated before
PerformanceIndex index = element.getPerformanceForCategoryTotals(currencyCode, interval);
return valueProviderTotal.apply(index);
}
else if (collector == null)
return null;

return collectValue(element.getChildren(), currencyCode, interval);
else
return collectValue(element.getChildren(), currencyCode, interval);
}
else if (element.isGroupByTaxonomy())
{
if (collector == null)
if (collector == null && valueProviderTotal != null)
{
// assumption: performance index has been calculated before
PerformanceIndex index = element.getPerformanceForCategoryTotals(currencyCode, interval);
return valueProviderTotal.apply(index);
}
else if (collector == null)
return null;

return collectValue(element.getChildren().flatMap(Element::getChildren), currencyCode, interval);
else
return collectValue(element.getChildren().flatMap(Element::getChildren), currencyCode, interval);
}
else
{
Expand All @@ -1327,6 +1385,7 @@ private final class ReportingPeriodLabelProvider extends OptionLabelProvider<Rep
implements Comparator<Object>
{
private boolean showColorAndArrows;
private boolean calculateTotalsPerformance = false;
private ElementValueProvider valueProvider;
private Function<Element, String> currencyProvider;

Expand All @@ -1341,6 +1400,13 @@ public ReportingPeriodLabelProvider(Function<LazySecurityPerformanceRecord, Lazy
this(new ElementValueProvider(valueProvider, collector), null, showUpAndDownArrows);
}

public ReportingPeriodLabelProvider(Function<LazySecurityPerformanceRecord, LazyValue<?>> valueProvider,
boolean showUpAndDownArrows, Function<PerformanceIndex, ?> valueProviderTotal)
{
this(new ElementValueProvider(valueProvider, null, valueProviderTotal), null, showUpAndDownArrows);
this.calculateTotalsPerformance = true;
}

public ReportingPeriodLabelProvider(ElementValueProvider valueProvider, boolean showUpAndDownArrows)
{
this(valueProvider, null, showUpAndDownArrows);
Expand Down Expand Up @@ -1378,7 +1444,7 @@ private Object getValue(Object e, ReportingPeriod option)
String currencyCode = currencyProvider != null ? currencyProvider.apply(element)
: model.getCurrencyConverter().getTermCurrency();

model.calculatePerformanceAndInjectIntoElements(currencyCode, interval);
model.calculatePerformanceAndInjectIntoElements(currencyCode, interval, calculateTotalsPerformance);

return valueProvider.getValue(element, currencyCode, interval);
}
Expand Down