Gepostet in Portfolio Tracking
Rebalancing App: Tagbasierte / summierte Positionen sollten unterstützt werden
Nerd Feature Request:
Ich würde mich freuen, wenn es eine App / Funktion gäbe, die ein Rebalancing auf Grundlage aggregierter bzw. summierter Positionen ermöglicht (gerne mit Hilfe von Tags, die ich bereits nutze).
Wie die Rebalancing App, nur in „fortgeschritten“. Bislang löse ich dies über ein JavaScript Snippet in der Browserkonsole, aber das ist nervig.
Wie folgt das Problem:
Mein Portfolio hat vier Positionen. Zwei Positionen bilden jeweils den MSCI World ab (ein alter gebührenteurer ETF von iShares, sowie ein neuerer günstiger von Vanguard). Gleiches gilt für Emerging Markets.
Ich will nur die zwei gebührengünstigen ETF-Positionen besparen durch Nur-Zukauf-Rebalancing. Die alten teuren ETFs sollen nicht mehr erhöht werden, aber auch nicht verringert werden (Hold).
World-Summe soll im Rebalanced-Zustand 70% betragen, Emerging-Summe 30%.
Ich habe die Positionen bereits mit Tags gruppiert, aber afaik unterstützt die Rebalancing-App diese tagbasierten Aggregationen noch nicht … ?
Wäre cool, sowas anzubieten. :) Denn ich kann leider in klassischen Rebalancing-Tools nur je Position einen Ziel-Anteil angeben und keine aggregierten Werte berechnen lassen.
Hier noch das JavaScript-Snippet (Sprache muss dafür US sein):
// Helper to find the correct section only once and cache it
let portfolioSection = null;
function getWertpapiereSection() {
if (portfolioSection) return portfolioSection;
const allElements = document.querySelectorAll('*');
let h2Found = false;
for (let el of allElements) {
// 1. Look for the H2 containing the target text
if (el.tagName === 'H2' && el.textContent.includes('Securities')) {
h2Found = true;
}
// 2. Find the very first <section> after that H2
if (h2Found && el.tagName === 'SECTION') {
portfolioSection = el;
return portfolioSection;
}
}
return null;
}
function getTableValue(search_string) {
const section = getWertpapiereSection();
if (!section) {
console.warn('Section after H2 "Securities" not found.');
return 0;
}
// Get all elements inside the section in document order
const allElements = Array.from(section.querySelectorAll('*'));
// 3. Find the innermost element of the FIRST occurrence containing the text
const textElement = allElements.find(el =>
el.textContent.includes(search_string) &&
!Array.from(el.children).some(child => child.textContent.includes(search_string))
);
if (!textElement) {
console.warn(`Element with text "${search_string}" not found.`);
return 0;
}
// 4. Find the NEXT element with the specific data-testid attribute
const startIndex = allElements.indexOf(textElement);
const remainingElements = allElements.slice(startIndex);
const priceElement = remainingElements.find(el =>
el.hasAttribute &&
el.getAttribute('data-testid') === 'monetary-value'
);
if (!priceElement) {
console.warn(`Price element for "${search_string}" not found next to it.`);
return 0;
}
try {
// Extract the raw string (e.g. "€99,654.84")
const rawText = priceElement.textContent;
// Keep only numbers up to the decimal point (removes cents and formatting)
const cleanedString = rawText.split('.')[0].replace(/[^0-9]/g, '');
// Convert to integer (base 10)
return parseInt(cleanedString, 10);
} catch (error) {
console.error(`Structure error parsing value for "${search_string}":`, error.message);
return 0;
}
}
// --- Rebalancing Logic ---
let kapital_e = getTableValue('iShares MSCI Emerging Markets UCITS') + getTableValue('Vanguard FTSE Emerging Markets UCITS');
let kapital_w = getTableValue('iShares MSCI World UCITS ETF') + getTableValue('Vanguard FTSE Developed World UCITS');
console.log('World Bestand: ' + kapital_w);
console.log('Emerging Bestand: ' + kapital_e);
if (kapital_w + kapital_e > 0) {
let x_w = (0.7 * kapital_e - 0.3 * kapital_w) / 0.3;
let x_e = (0.3 * kapital_w - 0.7 * kapital_e) / 0.7;
if (x_w > 100) {
console.log('World kaufen: ' + parseInt(x_w, 10));
}
if (x_e > 100) {
console.log('Emerging kaufen: ' + parseInt(x_e, 10));
}
} else {
console.log('Kein Bestand gefunden, Rebalancing nicht möglich.');
}