Skip to content

Commit 9df3d33

Browse files
Maxr1998meigelb
andauthored
Support ING Wertpapiere as source (#14)
* Support ING Wertpapiere as source * Address review feedback for ING source (#1) --------- Co-authored-by: meigelb <94784984+meigelb@users.noreply.github.com>
1 parent bb7262d commit 9df3d33

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

docs/index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@
2626
2727
- Jameica neu starten
2828
29+
## ing.de
30+
31+
- [ing.js](https://raw.githubusercontent.com/faiteanu/JavaStockQuotes/master/js/ing.js) (zuletzt geändert 21.03.2026)
32+
herunterladen und unter Windows speichern unter
33+
`C:\Users\{USERNAME}\.jameica\hibiscus.depotviewer\js`
34+
Unter Linux das entsprechende Benutzer-Verzeichnis wählen.
35+
36+
- Jameica neu starten
37+
2938
## PortfolioReport
3039
3140
- [portfolioreport.js](https://raw.githubusercontent.com/faiteanu/JavaStockQuotes/master/js/portfolioreport.js) (zuletzt geändert 18.01.2025)

js/ing.js

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Script for Hibiscus Depot Viewer
2+
// Original version by Maxr1998
3+
4+
var Logger = Packages.de.willuhn.logging.Logger;
5+
var ArrayList = java.util.ArrayList;
6+
var JDate = java.util.Date;
7+
var BigDecimal = java.math.BigDecimal;
8+
9+
var fetcher;
10+
var isin;
11+
var exchangeCodeMap = {}
12+
13+
function getAPIVersion() {
14+
return "1";
15+
};
16+
17+
function getVersion() {
18+
return "2026-03-21";
19+
};
20+
21+
function getName() {
22+
return "ING Wertpapiere";
23+
};
24+
25+
function getURL() {
26+
return "https://wertpapiere.ing.de";
27+
};
28+
29+
function prepare(fetch, search, startyear, startmon, startday, stopyear, stopmon, stopday) {
30+
Logger.info("Configuring...");
31+
fetcher = fetch;
32+
isin = search;
33+
34+
const webClient = fetcher.getWebClient(false);
35+
webClient.getOptions().setThrowExceptionOnFailingStatusCode(false);
36+
37+
try {
38+
Logger.debug("Requesting time ranges");
39+
//const pageTimeRanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/components-ng/chart?isins=" + isin);
40+
const pageTimeRanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/components/charttool/" + isin);
41+
const responseTimeRanges = JSON.parse(pageTimeRanges.getWebResponse().getContentAsString());
42+
43+
Logger.debug("Requesting exchanges and currency");
44+
const pageExchanges = webClient.getPage("https://component-api.wertpapiere.ing.de/api/v1/instrument-header?isinOrSearchTerm=" + isin + "&isKnownIsin=true&includeAvailableExchanges=true");
45+
const responseExchanges = JSON.parse(pageExchanges.getWebResponse().getContentAsString());
46+
}
47+
catch(error) {
48+
Logger.error("ISIN " + isin + " nicht gefunden bei " + getName());
49+
}
50+
51+
// Zeitraum
52+
var historyConfig = new Packages.jsq.config.Config("Historie");
53+
const periods = responseTimeRanges["chartPeriodTranslations"];
54+
periods.forEach(period => {
55+
if (period["chartPeriod"] != "Intraday") {
56+
historyConfig.addAuswahl(period["translation"], period["chartPeriod"]);
57+
}
58+
});
59+
60+
// Kursdetails: Hoch,Tief, Eröffnung
61+
var ohlcConfig = new Packages.jsq.config.Config("Kursdetails");
62+
ohlcConfig.addAuswahl("Keine", new Boolean(false));
63+
ohlcConfig.addAuswahl("Hoch-/Tief-/Eröffnungskurse", new Boolean(true));
64+
65+
// Handelsplatz
66+
const exchanges = responseExchanges["exchanges"];
67+
Logger.debug("Found " + exchanges.length + " exchanges");
68+
69+
var exchangeConfig = new Packages.jsq.config.Config("Handelsplatz");
70+
exchanges.forEach(exchange => {
71+
exchangeConfig.addAuswahl(exchange["exchangeName"], exchange["exchangeCode"]);
72+
Logger.debug("currency " + exchange["currencySymbol"] + " found at " + exchange["exchangeCode"] + " (" + exchange["exchangeName"] + ")");
73+
// remember infos of exchange for process()
74+
exchangeCodeMap[exchange["exchangeCode"]] = exchange;
75+
});
76+
77+
var cfgliste = new ArrayList();
78+
cfgliste.add(historyConfig);
79+
cfgliste.add(ohlcConfig);
80+
cfgliste.add(exchangeConfig);
81+
82+
return cfgliste;
83+
}
84+
85+
function process(config) {
86+
// default config
87+
var history = "OneMonth";
88+
var ohlc = "";
89+
var exchange = {
90+
"exchangeCode": "TGT",
91+
"exchangeName": "Direkthandel",
92+
"exchangeId": 2779,
93+
"currencySymbol": "EUR",
94+
"currencyId": 814
95+
};
96+
// read from saved config
97+
for (i = 0; i < config.size(); i++) {
98+
var cfg = config.get(i);
99+
Logger.info(cfg.toString());
100+
for (j = 0; j < cfg.getSelected().size(); j++) {
101+
var o = cfg.getSelected().get(j);
102+
if (cfg.getBeschreibung().equals("Historie")) {
103+
history = o.getObj();
104+
} else if (cfg.getBeschreibung().equals("Handelsplatz")) {
105+
const exchangeCode = o.getObj();
106+
if (exchangeCode in exchangeCodeMap) {
107+
exchange = exchangeCodeMap[exchangeCode];
108+
Logger.debug("currency at exchange " + exchangeCode + " is " + exchange["currencySymbol"]);
109+
}
110+
} else if (cfg.getBeschreibung().equals("Kursdetails")) {
111+
ohlc = o.getObj().valueOf() ? "&ohlc=true" : "";
112+
}
113+
}
114+
}
115+
116+
117+
// Fetch data
118+
var res = new ArrayList();
119+
120+
Logger.info("Fetching history " + history + " of " + isin + " at " + exchange["exchangeCode"]);
121+
const webClient = fetcher.getWebClient(false);
122+
//const url = "https://component-api.wertpapiere.ing.de/api/v1/charts/shm/" + isin + "?timeRange="+ history + "&exchangeId=" + exchangeId + "&currencyId=" + currencyId;
123+
const url = "https://component-api.wertpapiere.ing.de/api/v1/charts/charttooldata/" + isin + "?timeRange=" + history + "&exchangeId=" + exchange["exchangeId"] + "&exchangeCode=" + exchange["exchangeCode"] + "&currencyId=" + exchange["currencyId"] + ohlc;
124+
Logger.debug("request " + url)
125+
const page = webClient.getPage(url);
126+
const response = JSON.parse(page.getWebResponse().getContentAsString());
127+
const data = response["instruments"][0]["data"];
128+
const keys = response["instruments"][0]["keys"]; // meaning of elements in data ordered in the same way
129+
const keyMapping = {"x": "date",
130+
"y": "last",
131+
"open": "first",
132+
"high": "high",
133+
"low": "low",
134+
"close": "last"
135+
}; // translate keys to internal id in Datacontainer
136+
const noMapping = "nomapping"
137+
138+
Logger.info("Fetched " + data.length + " results.");
139+
140+
Logger.debug("keys=" + keys);
141+
let oldDate = new JDate();
142+
data.forEach(row => {
143+
// transform each row to a dict to match values with keys
144+
item = Object.fromEntries(
145+
keys.map((key, i) => [(key in keyMapping ? keyMapping[key] : noMapping), row[i]])
146+
);
147+
Logger.trace("item=" + JSON.stringify(item));
148+
// no need to consider response["instruments"][0]["currentTimezoneOffset"], since quotes are given in UTC
149+
const date = new JDate(item["date"]);
150+
151+
// Ensure there's only one result per day; assume historyItems are sorted by date
152+
if (res.isEmpty() || (date.getDate() != oldDate.getDate())) {
153+
var dc = new Packages.jsq.datastructes.Datacontainer();
154+
Object.entries(item).forEach(([mappedKey, value]) => {
155+
if (!["date", noMapping].includes(mappedKey)) {
156+
// add only values, where key could be mapped and is not date
157+
dc.put(mappedKey, new BigDecimal(value));
158+
}
159+
});
160+
161+
// if we found any value for mapable keys, we add the dc
162+
if (!dc.getMap().isEmpty()) {
163+
dc.put("currency", exchange["currencySymbol"]);
164+
dc.put("date", date);
165+
res.add(dc);
166+
}
167+
}
168+
oldDate = date;
169+
});
170+
171+
if (res.length > 0) {
172+
Logger.info("Received " + res.length + " historic quotes.");
173+
}
174+
else {
175+
Logger.error("No historic quotes found. " + (data.length > 0 ? "Maybe key mapping has changed." : ""));
176+
}
177+
178+
fetcher.setHistQuotes(res);
179+
}

0 commit comments

Comments
 (0)