diff --git a/docs/index.md b/docs/index.md index b788725..7e72ea9 100644 --- a/docs/index.md +++ b/docs/index.md @@ -26,6 +26,15 @@ - Jameica neu starten +## ing.de + +- [ing.js](https://raw.githubusercontent.com/faiteanu/JavaStockQuotes/master/js/ing.js) (zuletzt geändert 21.03.2026) + herunterladen und unter Windows speichern unter + `C:\Users\{USERNAME}\.jameica\hibiscus.depotviewer\js` + Unter Linux das entsprechende Benutzer-Verzeichnis wählen. + +- Jameica neu starten + ## PortfolioReport - [portfolioreport.js](https://raw.githubusercontent.com/faiteanu/JavaStockQuotes/master/js/portfolioreport.js) (zuletzt geändert 18.01.2025) diff --git a/js/ing.js b/js/ing.js new file mode 100644 index 0000000..86ae95a --- /dev/null +++ b/js/ing.js @@ -0,0 +1,179 @@ +// Script for Hibiscus Depot Viewer +// Original version by Maxr1998 + +var Logger = Packages.de.willuhn.logging.Logger; +var ArrayList = java.util.ArrayList; +var JDate = java.util.Date; +var BigDecimal = java.math.BigDecimal; + +var fetcher; +var isin; +var exchangeCodeMap = {} + +function getAPIVersion() { + return "1"; +}; + +function getVersion() { + return "2026-03-21"; +}; + +function getName() { + return "ING Wertpapiere"; +}; + +function getURL() { + return "https://wertpapiere.ing.de"; +}; + +function prepare(fetch, search, startyear, startmon, startday, stopyear, stopmon, stopday) { + Logger.info("Configuring..."); + fetcher = fetch; + isin = search; + + const webClient = fetcher.getWebClient(false); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + + try { + Logger.debug("Requesting time ranges"); + //const pageTimeRanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/components-ng/chart?isins=" + isin); + const pageTimeRanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/components/charttool/" + isin); + const responseTimeRanges = JSON.parse(pageTimeRanges.getWebResponse().getContentAsString()); + + Logger.debug("Requesting exchanges and currency"); + const pageExchanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/instrument-header?isinOrSearchTerm=" + isin + "&isKnownIsin=true&includeAvailableExchanges=true"); + const responseExchanges = JSON.parse(pageExchanges.getWebResponse().getContentAsString()); + } + catch(error) { + Logger.error("ISIN " + isin + " nicht gefunden bei " + getName()); + } + + // Zeitraum + var historyConfig = new Packages.jsq.config.Config("Historie"); + const periods = responseTimeRanges["chartPeriodTranslations"]; + periods.forEach(period => { + if (period["chartPeriod"] != "Intraday") { + historyConfig.addAuswahl(period["translation"], period["chartPeriod"]); + } + }); + + // Kursdetails: Hoch,Tief, Eröffnung + var ohlcConfig = new Packages.jsq.config.Config("Kursdetails"); + ohlcConfig.addAuswahl("Keine", new Boolean(false)); + ohlcConfig.addAuswahl("Hoch-/Tief-/Eröffnungskurse", new Boolean(true)); + + // Handelsplatz + const exchanges = responseExchanges["exchanges"]; + Logger.debug("Found " + exchanges.length + " exchanges"); + + var exchangeConfig = new Packages.jsq.config.Config("Handelsplatz"); + exchanges.forEach(exchange => { + exchangeConfig.addAuswahl(exchange["exchangeName"], exchange["exchangeCode"]); + Logger.debug("currency " + exchange["currencySymbol"] + " found at " + exchange["exchangeCode"] + " (" + exchange["exchangeName"] + ")"); + // remember infos of exchange for process() + exchangeCodeMap[exchange["exchangeCode"]] = exchange; + }); + + var cfgliste = new ArrayList(); + cfgliste.add(historyConfig); + cfgliste.add(ohlcConfig); + cfgliste.add(exchangeConfig); + + return cfgliste; +} + +function process(config) { + // default config + var history = "OneMonth"; + var ohlc = ""; + var exchange = { + "exchangeCode": "TGT", + "exchangeName": "Direkthandel", + "exchangeId": 2779, + "currencySymbol": "EUR", + "currencyId": 814 + }; + // read from saved config + for (i = 0; i < config.size(); i++) { + var cfg = config.get(i); + Logger.info(cfg.toString()); + for (j = 0; j < cfg.getSelected().size(); j++) { + var o = cfg.getSelected().get(j); + if (cfg.getBeschreibung().equals("Historie")) { + history = o.getObj(); + } else if (cfg.getBeschreibung().equals("Handelsplatz")) { + const exchangeCode = o.getObj(); + if (exchangeCode in exchangeCodeMap) { + exchange = exchangeCodeMap[exchangeCode]; + Logger.debug("currency at exchange " + exchangeCode + " is " + exchange["currencySymbol"]); + } + } else if (cfg.getBeschreibung().equals("Kursdetails")) { + ohlc = o.getObj().valueOf() ? "&ohlc=true" : ""; + } + } + } + + + // Fetch data + var res = new ArrayList(); + + Logger.info("Fetching history " + history + " of " + isin + " at " + exchange["exchangeCode"]); + const webClient = fetcher.getWebClient(false); + //const url = "https://component-api.wertpapiere.ing.de/api/v1/charts/shm/" + isin + "?timeRange="+ history + "&exchangeId=" + exchangeId + "¤cyId=" + currencyId; + const url = "https://component-api.wertpapiere.ing.de/api/v1/charts/charttooldata/" + isin + "?timeRange=" + history + "&exchangeId=" + exchange["exchangeId"] + "&exchangeCode=" + exchange["exchangeCode"] + "¤cyId=" + exchange["currencyId"] + ohlc; + Logger.debug("request " + url) + const page = webClient.getPage(url); + const response = JSON.parse(page.getWebResponse().getContentAsString()); + const data = response["instruments"][0]["data"]; + const keys = response["instruments"][0]["keys"]; // meaning of elements in data ordered in the same way + const keyMapping = {"x": "date", + "y": "last", + "open": "first", + "high": "high", + "low": "low", + "close": "last" + }; // translate keys to internal id in Datacontainer + const noMapping = "nomapping" + + Logger.info("Fetched " + data.length + " results."); + + Logger.debug("keys=" + keys); + let oldDate = new JDate(); + data.forEach(row => { + // transform each row to a dict to match values with keys + item = Object.fromEntries( + keys.map((key, i) => [(key in keyMapping ? keyMapping[key] : noMapping), row[i]]) + ); + Logger.trace("item=" + JSON.stringify(item)); + // no need to consider response["instruments"][0]["currentTimezoneOffset"], since quotes are given in UTC + const date = new JDate(item["date"]); + + // Ensure there's only one result per day; assume historyItems are sorted by date + if (res.isEmpty() || (date.getDate() != oldDate.getDate())) { + var dc = new Packages.jsq.datastructes.Datacontainer(); + Object.entries(item).forEach(([mappedKey, value]) => { + if (!["date", noMapping].includes(mappedKey)) { + // add only values, where key could be mapped and is not date + dc.put(mappedKey, new BigDecimal(value)); + } + }); + + // if we found any value for mapable keys, we add the dc + if (!dc.getMap().isEmpty()) { + dc.put("currency", exchange["currencySymbol"]); + dc.put("date", date); + res.add(dc); + } + } + oldDate = date; + }); + + if (res.length > 0) { + Logger.info("Received " + res.length + " historic quotes."); + } + else { + Logger.error("No historic quotes found. " + (data.length > 0 ? "Maybe key mapping has changed." : "")); + } + + fetcher.setHistQuotes(res); +}