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

Added adjusted internal rate of return #2975

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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 @@ -20,6 +20,7 @@
public class DataSeriesConfig implements WidgetConfig
{
private final WidgetDelegate<?> delegate;
private final boolean supportsDataSeries;
private final boolean supportsBenchmarks;
private final String label;
private final Dashboard.Config configurationKey;
Expand All @@ -29,18 +30,22 @@ public class DataSeriesConfig implements WidgetConfig

public DataSeriesConfig(WidgetDelegate<?> delegate, boolean supportsBenchmarks)
{
this(delegate, supportsBenchmarks, false, null, Messages.LabelDataSeries, Dashboard.Config.DATA_SERIES);
this(delegate, true, supportsBenchmarks, false, null, Messages.LabelDataSeries,
Dashboard.Config.DATA_SERIES);
}

public DataSeriesConfig(WidgetDelegate<?> delegate, boolean supportsBenchmarks, Predicate<DataSeries> predicate)
{
this(delegate, supportsBenchmarks, false, predicate, Messages.LabelDataSeries, Dashboard.Config.DATA_SERIES);
this(delegate, true, supportsBenchmarks, false, predicate, Messages.LabelDataSeries,
Dashboard.Config.DATA_SERIES);
}

protected DataSeriesConfig(WidgetDelegate<?> delegate, boolean supportsBenchmarks, boolean supportsEmptyDataSeries,
Predicate<DataSeries> predicate, String label, Dashboard.Config configurationKey)
protected DataSeriesConfig(WidgetDelegate<?> delegate, boolean supportsDataSeries, boolean supportsBenchmarks,
boolean supportsEmptyDataSeries, Predicate<DataSeries> predicate, String label,
Dashboard.Config configurationKey)
{
this.delegate = delegate;
this.supportsDataSeries = supportsDataSeries;
this.supportsBenchmarks = supportsBenchmarks;
this.label = label;
this.configurationKey = configurationKey;
Expand All @@ -60,6 +65,16 @@ public DataSeries getDataSeries()
return dataSeries;
}

protected void setDataSeries(DataSeries dataSeries)
{
this.dataSeries = dataSeries;
}

protected WidgetDelegate<?> getDelegate()
{
return delegate;
}

@Override
public void menuAboutToShow(IMenuManager manager)
{
Expand All @@ -70,7 +85,9 @@ public void menuAboutToShow(IMenuManager manager)
MenuManager subMenu = new MenuManager(label, configurationKey.name());
subMenu.add(new LabelOnly(dataSeries != null ? dataSeries.getLabel() : "-")); //$NON-NLS-1$
subMenu.add(new Separator());
subMenu.add(new SimpleAction(Messages.MenuSelectDataSeries, a -> doAddSeries(false)));

if (supportsDataSeries)
subMenu.add(new SimpleAction(Messages.MenuSelectDataSeries, a -> doAddSeries(false)));

if (supportsBenchmarks)
subMenu.add(new SimpleAction(Messages.MenuSelectBenchmarkDataSeries, a -> doAddSeries(true)));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package name.abuchen.portfolio.ui.views.dashboard;

import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;

import name.abuchen.portfolio.model.Dashboard;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.util.SimpleAction;

public class IRRDataSeriesConfig extends DataSeriesConfig
{

public IRRDataSeriesConfig(WidgetDelegate<?> delegate)
{
super(delegate, false, true, true, null, Messages.LabelBenchmarks,
Dashboard.Config.SECONDARY_DATA_SERIES);
}

@Override
public void menuAboutToShow(IMenuManager manager)
{
super.menuAboutToShow(manager);
if (getDataSeries() != null)
{
IMenuManager subMenu = manager.findMenuUsingPath(Dashboard.Config.SECONDARY_DATA_SERIES.name());
subMenu.add(new Separator());
subMenu.add(new SimpleAction(Messages.MenuReportingPeriodDelete, a -> removeBenchmark()));
}

}

private void removeBenchmark()
{
if (getDataSeries() == null)
return;

setDataSeries(null);
getDelegate().getWidget().getConfiguration().remove(Dashboard.Config.SECONDARY_DATA_SERIES.name());
getDelegate().getWidget().setLabel(WidgetFactory.valueOf(getDelegate().getWidget().getType()).getLabel());
getDelegate().update();
getDelegate().getClient().touch();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package name.abuchen.portfolio.ui.views.dashboard;

import java.time.LocalDate;
import java.util.function.Supplier;

import name.abuchen.portfolio.model.Dashboard.Widget;
import name.abuchen.portfolio.money.Values;
import name.abuchen.portfolio.ui.views.dataseries.DataSeries;
import name.abuchen.portfolio.util.Interval;

public class IRRWidget extends IndicatorWidget<Double>
{
public IRRWidget(Widget widget, DashboardData dashboardData)
{
super(widget, dashboardData, false, null);
this.setFormatter(Values.Percent2);

addConfig(new IRRDataSeriesConfig(this));
}

@Override
public Supplier<Double> getUpdateTask()
{
return () -> {
double irrBench = 0;
Interval reportingPeriod = get(ReportingPeriodConfig.class).getReportingPeriod()
.toInterval(LocalDate.now());
DataSeries dsBench = get(IRRDataSeriesConfig.class).getDataSeries();
if (dsBench != null)
{
irrBench = getDashboardData().calculate(dsBench, reportingPeriod).getPerformanceIRR();
}

double irr = getDashboardData().calculate(get(DataSeriesConfig.class).getDataSeries(), reportingPeriod)
.getPerformanceIRR();
return (irrBench != -1) ? (1 + irr) / (1 + irrBench) - 1 : irr - irrBench;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the business logic of the widget, and it’s wrong. Since the IRR is money-weighted, it is not enough to just subtract the benchmark; you need to correct the whole data series by the benchmark before calculating the IRR.

};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@ public enum WidgetFactory
return index.getFinalAccumulatedAnnualizedPercentage();
}).build()),

IRR(Messages.LabelIRR, Messages.ClientEditorLabelPerformance, //
(widget, data) -> IndicatorWidget.<Double>create(widget, data) //
.with(Values.Percent2) //
.with((ds, period) -> data.calculate(ds, period).getPerformanceIRR()) //
.withBenchmarkDataSeries(false) //
.build()),
IRR(Messages.LabelIRR, Messages.ClientEditorLabelPerformance, IRRWidget::new),

ABSOLUTE_CHANGE(Messages.LabelAbsoluteChange, Messages.LabelStatementOfAssets, //
(widget, data) -> IndicatorWidget.<Long>create(widget, data) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ public class ExcessReturnDataSeriesConfig extends DataSeriesConfig
{
public ExcessReturnDataSeriesConfig(WidgetDelegate<?> delegate)
{
super(delegate, true, true, null, Messages.LabelExcessReturnBaselineDataSeries,
Dashboard.Config.SECONDARY_DATA_SERIES);
super(delegate, true, true, true, null,
Messages.LabelExcessReturnBaselineDataSeries, Dashboard.Config.SECONDARY_DATA_SERIES);
}

}