From 8cfb3172db6911c84050eff55608be7afe295a27 Mon Sep 17 00:00:00 2001 From: Dominique Lasserre Date: Sun, 11 Sep 2022 23:08:39 +0200 Subject: [PATCH] Added adjusted internal rate of return - Add new widget Adjusted IRR that allows to set benchmark to e.g. consumer price index to get inflation adjusted IRR. --- .../name/abuchen/portfolio/ui/Messages.java | 1 + .../abuchen/portfolio/ui/messages.properties | 2 + .../portfolio/ui/messages_de.properties | 2 + .../ui/views/dashboard/DataSeriesConfig.java | 19 +++++++-- .../ui/views/dashboard/IRRAdjustedWidget.java | 39 +++++++++++++++++++ .../ui/views/dashboard/WidgetDelegate.java | 7 +++- .../ui/views/dashboard/WidgetFactory.java | 2 + .../heatmap/ExcessReturnDataSeriesConfig.java | 2 +- 8 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/IRRAdjustedWidget.java diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/Messages.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/Messages.java index 074adfbffd..12487adc32 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/Messages.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/Messages.java @@ -625,6 +625,7 @@ public class Messages extends NLS public static String LabelInvestedCapital; public static String LabelInvestmentPlans; public static String LabelIRR; + public static String LabelIRRAdjusted; public static String LabelLanguage; public static String LabelLanguageAutomatic; public static String LabelLayout; diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages.properties b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages.properties index e4727066f6..385fd4655e 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages.properties +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages.properties @@ -1274,6 +1274,8 @@ LabelHistoricalReturnsAndVolatiltity = Historical Returns and Volatility LabelIRR = Internal Rate of Return (IRR) +LabelIRRAdjusted = Adjusted Internal Rate of Return (IRR) + LabelIncludeSecuritiesInPieChart = Include investment vehicles LabelIncludeUnassignedCategoryInCharts = Include 'Without Classification' diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages_de.properties b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages_de.properties index 7a7a47afab..3ed1bfa72d 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages_de.properties +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/messages_de.properties @@ -1259,6 +1259,8 @@ LabelHistoricalReturnsAndVolatiltity = Historische Performance und Volatilit\u00 LabelIRR = Interner Zinsfu\u00DF (IZF) +LabelIRRAdjusted = Angepasster Interner Zinsfu\u00DF (IZF) + LabelIncludeSecuritiesInPieChart = Wertpapiere einbeziehen LabelIncludeUnassignedCategoryInCharts = 'Ohne Klassifizierung' einbeziehen diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/DataSeriesConfig.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/DataSeriesConfig.java index e1983af18d..738bc415a6 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/DataSeriesConfig.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/DataSeriesConfig.java @@ -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; @@ -29,18 +30,26 @@ public class DataSeriesConfig implements WidgetConfig public DataSeriesConfig(WidgetDelegate delegate, boolean supportsBenchmarks) { - this(delegate, supportsBenchmarks, false, null, Messages.LabelDataSeries, Dashboard.Config.DATA_SERIES); + this(delegate, supportsBenchmarks, false, null, Messages.LabelDataSeries, true, Dashboard.Config.DATA_SERIES); + } + + public DataSeriesConfig(WidgetDelegate delegate) + { + this(delegate, true, true, null, Messages.LabelBenchmarks, false, Dashboard.Config.DATA_SERIES); } public DataSeriesConfig(WidgetDelegate delegate, boolean supportsBenchmarks, Predicate predicate) { - this(delegate, supportsBenchmarks, false, predicate, Messages.LabelDataSeries, Dashboard.Config.DATA_SERIES); + this(delegate, supportsBenchmarks, false, predicate, Messages.LabelDataSeries, true, + Dashboard.Config.DATA_SERIES); } protected DataSeriesConfig(WidgetDelegate delegate, boolean supportsBenchmarks, boolean supportsEmptyDataSeries, - Predicate predicate, String label, Dashboard.Config configurationKey) + Predicate predicate, String label, boolean supportsDataSeries, + Dashboard.Config configurationKey) { this.delegate = delegate; + this.supportsDataSeries = supportsDataSeries; this.supportsBenchmarks = supportsBenchmarks; this.label = label; this.configurationKey = configurationKey; @@ -70,7 +79,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))); diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/IRRAdjustedWidget.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/IRRAdjustedWidget.java new file mode 100644 index 0000000000..dd38814640 --- /dev/null +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/IRRAdjustedWidget.java @@ -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 IRRAdjustedWidget extends IndicatorWidget +{ + public IRRAdjustedWidget(Widget widget, DashboardData dashboardData) + { + super(widget, dashboardData, false, null); + this.setFormatter(Values.Percent2); + + addConfig(new DataSeriesConfig(this)); + } + + @Override + public Supplier getUpdateTask() + { + return () -> { + double irrBench = 0; + Interval reportingPeriod = get(ReportingPeriodConfig.class).getReportingPeriod() + .toInterval(LocalDate.now()); + DataSeries dsBench = get(DataSeriesConfig.class, 1).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; + }; + } +} diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetDelegate.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetDelegate.java index fd715f9e22..2ccb435145 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetDelegate.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetDelegate.java @@ -52,7 +52,12 @@ public DashboardData getDashboardData() public C get(Class type) { - return type.cast(config.stream().filter(c -> type.equals(c.getClass())).findAny() + return get(type, 0); + } + + public C get(Class type, int skip) + { + return type.cast(config.stream().filter(c -> type.equals(c.getClass())).skip(skip).findAny() .orElseThrow(IllegalArgumentException::new)); } diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetFactory.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetFactory.java index 4e0c47f88e..c063c8a7dd 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetFactory.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/WidgetFactory.java @@ -65,6 +65,8 @@ public enum WidgetFactory .withBenchmarkDataSeries(false) // .build()), + IRR_ADJUSTED(Messages.LabelIRRAdjusted, Messages.ClientEditorLabelPerformance, IRRAdjustedWidget::new), + ABSOLUTE_CHANGE(Messages.LabelAbsoluteChange, Messages.LabelStatementOfAssets, // (widget, data) -> IndicatorWidget.create(widget, data) // .with(Values.Amount) // diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/heatmap/ExcessReturnDataSeriesConfig.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/heatmap/ExcessReturnDataSeriesConfig.java index a36a34d263..2d283b0421 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/heatmap/ExcessReturnDataSeriesConfig.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/dashboard/heatmap/ExcessReturnDataSeriesConfig.java @@ -10,7 +10,7 @@ public class ExcessReturnDataSeriesConfig extends DataSeriesConfig public ExcessReturnDataSeriesConfig(WidgetDelegate delegate) { super(delegate, true, true, null, Messages.LabelExcessReturnBaselineDataSeries, - Dashboard.Config.SECONDARY_DATA_SERIES); + true, Dashboard.Config.SECONDARY_DATA_SERIES); } }