Skip to content

Commit

Permalink
Enable online sync of existing securities with etf-data.com
Browse files Browse the repository at this point in the history
Co-authored-by: Marvin Frick <marvin.frick@shopify.com>
Co-authored-by: Andreas Buchen <andreas.buchen@gmail.com>
Issue: portfolio-performance#1908
  • Loading branch information
2 people authored and Lennix committed Feb 22, 2021
1 parent 986c705 commit 118709c
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 10 deletions.
3 changes: 3 additions & 0 deletions name.abuchen.portfolio.bootstrap/Application.e4xmi
Expand Up @@ -85,6 +85,7 @@
</children>
<children xsi:type="menu:MenuSeparator" xmi:id="_OvJsIL3OEeqoTtTaIzseTQ" elementId="name.abuchen.portfolio.bootstrap.menuseparator.6"/>
<children xsi:type="menu:HandledMenuItem" xmi:id="_PV6KIL3OEeqoTtTaIzseTQ" elementId="name.abuchen.portfolio.ui.menu.online.uploadToDivvyDiary" label="Upload to DivvyDiary.com" iconURI="platform:/plugin/name.abuchen.portfolio.ui/icons/divvydiary.com-logo.png" command="_ZWCyUL3OEeqoTtTaIzseTQ"/>
<children xsi:type="menu:HandledMenuItem" xmi:id="_uCcK8E9wEeuKH4ThcNC3ug" elementId="name.abuchen.portfolio.bootstrap.handledmenuitem.syncfrometf-datacom" label="Sync from etf-data.com" iconURI="platform:/plugin/name.abuchen.portfolio.ui/icons/etf-data_logo.png" command="_BPIxsE9jEeuKH4ThcNC3ug"/>
</children>
<children xsi:type="menu:Menu" xmi:id="_6KeHEBiPEeOR1rNFCzC82A" elementId="name.abuchen.portfolio.ui.menu.help" label="%menu.help.label">
<children xsi:type="menu:HandledMenuItem" xmi:id="_oALicB3VEeOYjJVcrtNJyA" elementId="name.abuchen.portfolio.ui.menu.help.about" label="%command.about.name" tooltip="%command.about.tooltip" command="_Vr7H8B3VEeOYjJVcrtNJyA"/>
Expand Down Expand Up @@ -156,6 +157,7 @@
<handlers xmi:id="_VFcfMBM9EeqsXLK6ns2Lug" elementId="name.abuchen.portfolio.ui.handler.saveErrorLog" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.handlers.SaveErrorLogHandler" command="_PZoy8BM9EeqsXLK6ns2Lug"/>
<handlers xmi:id="_QjA2cL3OEeqoTtTaIzseTQ" elementId="name.abuchen.portfolio.ui.handler.uploadToDivvyDiary" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.handlers.UploadToDivvyDiaryHandler" command="_ZWCyUL3OEeqoTtTaIzseTQ"/>
<handlers xmi:id="_YLz7IDFOEeuGXeKVI3KJtQ" elementId="name.abuchen.portfolio.handler.selectAll" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.handlers.SelectAllHandler" command="_gxx18DFPEeuGXeKVI3KJtQ"/>
<handlers xmi:id="_FWEK0E9jEeuKH4ThcNC3ug" elementId="name.abuchen.portfolio.ui.handler.downloadETFData" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.handlers.DownloadETFDataHandler" command="_BPIxsE9jEeuKH4ThcNC3ug"/>
<bindingTables xmi:id="_uK6dcBiSEeO8gYEHAOvLsA" elementId="" bindingContext="_7d8q4RjAEeO8gYEHAOvLsA">
<bindings xmi:id="_yNkakBiSEeO8gYEHAOvLsA" elementId="" keySequence="M1+O" command="_3CjQwBfHEeOders_POVQHQ"/>
<bindings xmi:id="_0WsqQBiSEeO8gYEHAOvLsA" elementId="" keySequence="M1+N" command="_LiZuIBiOEeOR1rNFCzC82A"/>
Expand Down Expand Up @@ -236,6 +238,7 @@
<commands xmi:id="_PZoy8BM9EeqsXLK6ns2Lug" elementId="name.abuchen.portfolio.ui.command.saveErrorLog" commandName="saveErrorLog"/>
<commands xmi:id="_ZWCyUL3OEeqoTtTaIzseTQ" elementId="name.abuchen.portfolio.ui.command.uploadToDivvyDiary" commandName="uploadToDivvyDiary"/>
<commands xmi:id="_gxx18DFPEeuGXeKVI3KJtQ" elementId="name.abuchen.portfolio.ui.command.selectAll" commandName="selectAll"/>
<commands xmi:id="_BPIxsE9jEeuKH4ThcNC3ug" elementId="name.abuchen.portfolio.ui.command.downloadETFData" commandName="downloadETFData"/>
<addons xmi:id="_4SwvYLOQEeWe1a5u3oOf1Q" elementId="name.abuchen.portfolio.ui.addon.proxy" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.addons.ProxyAddon"/>
<addons xmi:id="_B_-6cKH7EeO9F5tUX5UqjQ" elementId="name.abuchen.portfolio.ui.addon.log" contributionURI="bundleclass://name.abuchen.portfolio.ui/name.abuchen.portfolio.ui.addons.StartupAddon"/>
<addons xmi:id="_D8SDoRfFEeOders_POVQHQ" elementId="org.eclipse.e4.core.commands.service" contributionURI="bundleclass://org.eclipse.e4.core.commands/org.eclipse.e4.core.commands.CommandServiceAddon"/>
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added name.abuchen.portfolio.ui/icons/etf-data_logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,28 @@
package name.abuchen.portfolio.ui.handlers;

import javax.inject.Named;

import org.eclipse.e4.core.di.annotations.CanExecute;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.ui.basic.MPart;
import org.eclipse.e4.ui.services.IServiceConstants;
import org.eclipse.swt.widgets.Shell;

import name.abuchen.portfolio.ui.jobs.SyncETFDataJob;

public class DownloadETFDataHandler
{
@CanExecute
boolean isVisible(@Named(IServiceConstants.ACTIVE_PART) MPart part)
{
return MenuHelper.isClientPartActive(part);
}

@Execute
public void execute(@Named(IServiceConstants.ACTIVE_PART) MPart part,
@Named(IServiceConstants.ACTIVE_SHELL) Shell shell)
{
MenuHelper.getActiveClientInput(part)
.ifPresent(clientInput -> new SyncETFDataJob(clientInput.getClient()).schedule());
}
}
@@ -0,0 +1,75 @@
package name.abuchen.portfolio.ui.jobs;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

import com.google.common.base.Strings;
import com.ibm.icu.text.MessageFormat;

import name.abuchen.portfolio.model.Client;
import name.abuchen.portfolio.model.Security;
import name.abuchen.portfolio.online.SecuritySearchProvider.ResultItem;
import name.abuchen.portfolio.online.impl.ETFDataCom;
import name.abuchen.portfolio.ui.Messages;
import name.abuchen.portfolio.ui.PortfolioPlugin;

public final class SyncETFDataJob extends AbstractClientJob
{
public SyncETFDataJob(Client client)
{
super(client, Messages.JobLabelSyncSecuritiesOnline);
}

@Override
protected IStatus run(IProgressMonitor monitor)
{
List<Security> toBeSynced = getClient().getSecurities().stream()
.filter(s -> !Strings.isNullOrEmpty(s.getIsin())).collect(Collectors.toList());

if (toBeSynced.isEmpty())
return Status.OK_STATUS;

monitor.beginTask(MessageFormat.format(Messages.JobLabelSyncSecuritiesOnline, "https://etf-data.com"), //$NON-NLS-1$
toBeSynced.size());

boolean isDirty = false;

ETFDataCom etfdata = new ETFDataCom();

for (Security security : toBeSynced)
{
monitor.worked(1);

try
{
List<ResultItem> items = etfdata.search(security.getIsin());

if (!items.isEmpty())
{
boolean hasUpdate = ETFDataCom.updateWith(security, getClient().getSettings(), items.get(0));
isDirty = isDirty || hasUpdate;
}
else
{
PortfolioPlugin.info(
MessageFormat.format("No etf-data.com information found for ''{0}'' with ISIN {1}", //$NON-NLS-1$
security.getName(), security.getIsin()));
}
}
catch (IOException e)
{
PortfolioPlugin.log(e);
}
}

if (isDirty)
getClient().markDirty();

return Status.OK_STATUS;
}
}
Expand Up @@ -34,7 +34,8 @@ protected IStatus run(IProgressMonitor monitor)
if (toBeSynced.isEmpty())
return Status.OK_STATUS;

monitor.beginTask(Messages.JobLabelSyncSecuritiesOnline, toBeSynced.size());
monitor.beginTask(MessageFormat.format(Messages.JobLabelSyncSecuritiesOnline, "https://portfolio-report.net"), //$NON-NLS-1$
toBeSynced.size());

boolean isDirty = false;

Expand Down
Expand Up @@ -880,7 +880,7 @@ InvestmentPlanTypeDeposit = Deposit

JobLabelAutoSave = Saving backup file

JobLabelSyncSecuritiesOnline = Sync investment vehicles with https://portfolio-report.net
JobLabelSyncSecuritiesOnline = Sync investment vehicles with {0}

JobLabelUpdateCPI = Update Consumer Price Indices

Expand Down
Expand Up @@ -873,7 +873,7 @@ InvestmentPlanTypeDeposit = Einzahlung

JobLabelAutoSave = Sicherungsdatei speichern

JobLabelSyncSecuritiesOnline = Wertpapiere mit https://portfolio-report.net abgleichen
JobLabelSyncSecuritiesOnline = Wertpapiere mit {0} abgleichen

JobLabelUpdateCPI = Verbraucherpreise aktualisieren

Expand Down
Expand Up @@ -848,7 +848,7 @@ InvestmentPlanTypeDeposit = D\u00E9p\u00F4t

JobLabelAutoSave = Sauvegarde du fichier de r\u00E9cup\u00E9ration

JobLabelSyncSecuritiesOnline = Synchroniser les v\u00E9hicules d'investissement avec https://portfolio-report.net
JobLabelSyncSecuritiesOnline = Synchroniser les v\u00E9hicules d'investissement avec {0}

JobLabelUpdateCPI = Mettre \u00E0 jour les Indices des Prix \u00E0 la Consommation

Expand Down
Expand Up @@ -863,7 +863,7 @@ InvestmentPlanTypeDeposit = Storting

JobLabelAutoSave = Back-upbestand opslaan

JobLabelSyncSecuritiesOnline = Synchroniseer beleggingsvehikels met https://portfolio-report.net
JobLabelSyncSecuritiesOnline = Synchroniseer beleggingsvehikels met {0}

JobLabelUpdateCPI = Update consumentenprijsindexen

Expand Down
Expand Up @@ -867,7 +867,7 @@ InvestmentPlanTypeDeposit = Dep\u00F3sito

JobLabelAutoSave = Salvando arquivo de backup

JobLabelSyncSecuritiesOnline = Sincronize ve\u00EDculos de investimento com https://portfolio-report.net
JobLabelSyncSecuritiesOnline = Sincronize ve\u00EDculos de investimento com {0}

JobLabelUpdateCPI = Atualizar \u00EDndices de pre\u00E7os ao consumidor

Expand Down
Expand Up @@ -15,6 +15,8 @@
import org.json.simple.JSONValue;
import org.osgi.framework.FrameworkUtil;

import com.google.common.base.Objects;

import name.abuchen.portfolio.model.AttributeType;
import name.abuchen.portfolio.model.AttributeType.PercentConverter;
import name.abuchen.portfolio.model.AttributeType.StringConverter;
Expand Down Expand Up @@ -164,8 +166,10 @@ private Map<String, Object> attributeMapping()
return attributeMapping;
}

private Attributes updateAttributes(Attributes attributes, ClientSettings settings)
private boolean updateAttributes(Attributes attributes, ClientSettings settings)
{
boolean isDirty = false;

for (Map.Entry<String, Object> id2value : attributeMapping().entrySet())
{
AttributeType attribute = settings.getAttributeTypes()
Expand Down Expand Up @@ -207,10 +211,14 @@ else if (id2value.getValue() instanceof String)
return newAttribute;
});

attributes.put(attribute, id2value.getValue());
Object newValue = id2value.getValue();

Object oldValue = attributes.put(attribute, newValue);

isDirty = isDirty || !Objects.equal(oldValue, newValue);
}

return attributes;
return isDirty;
}

private void setInfo(Security security)
Expand All @@ -237,10 +245,15 @@ public Security create(ClientSettings settings)
Security security = new Security();

setInfo(security);
security.setAttributes(updateAttributes(security.getAttributes(), settings));
updateAttributes(security.getAttributes(), settings);

return security;
}

public boolean update(Security security, ClientSettings settings)
{
return updateAttributes(security.getAttributes(), settings);
}
}

public static final String PROVIDER_NAME = "ETF-Data.com"; //$NON-NLS-1$
Expand Down Expand Up @@ -269,4 +282,12 @@ private List<ResultItem> readItems(String jsonBlob)

return onlineItems;
}

public static boolean updateWith(Security security, ClientSettings settings, ResultItem item)
{
if (!(item instanceof OnlineItem))
throw new IllegalArgumentException();

return ((OnlineItem) item).update(security, settings);
}
}

0 comments on commit 118709c

Please sign in to comment.