您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Userscript, das den Download des aktuellen Depots bei Scalable Capital als CSV-Datei erlaubt.
// ==UserScript== // @name Scalable Capital Depot Export // @namespace http://tampermonkey.net/ // @version 0.1 // @description Userscript, das den Download des aktuellen Depots bei Scalable Capital als CSV-Datei erlaubt. // @author https://github.com/lime-scripts // @license MIT // @match https://de.scalable.capital/** // @icon https://www.google.com/s2/favicons?sz=64&domain=scalable.capital // @grant GM_registerMenuCommand // ==/UserScript== (function () { 'use strict'; GM_registerMenuCommand("Export Depot CSV", function () { const positions = findPositions(); const csv = toCsv(positions); downloadCsv(csv, "ScalableNeu_depot_export_" + (new Date().toISOString().split(".")[0]) + ".csv"); }); function isObject(obj) { return typeof obj === 'object' && obj !== null; } function findPositions() { let resultsMap = {}; function visit(node) { if (!node) { return; } else if (Array.isArray(node)) { for (const subNode of node) { visit(subNode); } } else if (isObject(node)) { if (node["isin"] && node["inventory"]) { resultsMap[node["isin"]] = { ...node }; } else { for (const key of Object.keys(node)) { if (["children", "props", "security", "items"].includes(key) || key.startsWith("__reactProps")) { visit(node[key]); } } } } if (node.childNodes) { node.childNodes.forEach(n => { visit(n); }); } } visit(document.body); const positions = Array.from(Object.values(resultsMap)).map(pos => ({ isin: pos.isin, name: pos.name, amount: pos.inventory.position?.filled, price: pos.inventory.position?.fifoPrice, data: pos })); positions.sort((a, b) => (a.name ?? "").localeCompare(b.name ?? "")); console.log(positions); console.log(positions.length, "Positionen"); return positions; } function toCsv(rows) { const SEP = ";"; const LINE_SEP = "\n"; const csvRows = []; for (let i = -1; i < rows.length; i++) { const row = rows[i]; const csvRow = Array(4).fill(""); csvRow[0] = i >= 0 ? row.name : "Name"; csvRow[1] = i >= 0 ? row.isin : "ISIN"; csvRow[2] = i >= 0 ? "" + row.amount : "Anzahl"; csvRow[3] = i >= 0 ? "" + row.price : "Preis"; csvRows.push(csvRow); } const csv = csvRows.map(row => row.map(val => val.replaceAll(SEP, "")).join(SEP)).join(LINE_SEP); return csv; } function toCsvBaader(rows) { const SEP = ";"; const LINE_SEP = "\n"; const COL_COUNT = 63; const HEADER = "XXX-LFDNR;XXX-SNR;XXX-PFNR;XXX-DENR;XXX-DENR-EXT;XXX-DEPSPERR;XXX-WPBEZK;XXX-WPBEZ1;XXX-WPBEZ2;XXX-WPBEZ3;XXX-WPBEZ4;XXX-WPNR;XXX-WPNRID-D;XXX-WPNRID-DBOE;XXX-KONTNR;XXX-KONTRAKT;XXX-DATFAELL;XXX-STRIKE;XXX-KZCP;XXX-SERIE;XXX-NOTIER;XXX-WHG;XXX-NW-M;XXX-NWSP-M;XXX-EINKURS-M;XXX-AKTKURS-M;XXX-AKTKURSD-M;XXX-KW-M;XXX-KWB-M;XXX-ABGR-M;XXX-ABGRB-M;XXX-FAKTORI;XXX-FAKTORP;XXX-EINKURSB-M;XXX-KONTBEZ;XXX-DEPOTLANG;XXX-NAME1;XXX-NAME2;XXX-MONJAHR;XXX-KURSB;XXX-KFAKTOR;XXX-BEWMET;XXX-PRAENOT;XXX-TUVIP;XXX-WPENDF;XXX-PFBEZ1;XXX-PFBEZ2;XXX-UNDERLYING;XXX-DATUM;XXX-VVSNR;XXX-WPART;XXX-UNDERU;XXX-BLOOMBERGK;XXX-VERFALLSTAG;XXX-VERSIONSNUMM;XXX-AUSUEBUNG;XXX-NWJUR-M;XXX-UTIPOS;XXX-KURSEIND-M;XXX-KWEEUR-M;XXX-KWBEL;XXX-KWBELB"; const csvRows = []; let rowCounter = 0; for (const row of rows) { rowCounter++; const csvRow = Array(COL_COUNT).fill(""); csvRow[0] = "" + rowCounter; csvRow[7] = row.name; csvRow[11] = row.isin; csvRow[22] = ("" + row.amount).replaceAll(".", ","); csvRow[24] = ("" + row.price).replaceAll(".", ","); csvRows.push(csvRow); } const csv = HEADER + LINE_SEP + csvRows.map(row => row.map(val => val.replaceAll(SEP, "")).join(SEP)).join(LINE_SEP); return csv; } function downloadCsv(csv, filename) { const data = "data:text/csv;charset=utf-8," + csv; const link = document.createElement("a"); link.setAttribute("href", encodeURI(data)); link.setAttribute("download", filename); document.body.appendChild(link); link.click(); } })();