Created
December 25, 2021 14:24
-
-
Save timotgl/670b5e6d4d6abe276c445d298bcdfa01 to your computer and use it in GitHub Desktop.
Calculate optimal amount of ETF shares to sell to take advantage of the german "Sparer-Pauschbetrag" (Node.js)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Optimal amount of profit (in EUR) to be gained from ETF sale | |
const optimalProfit = 1144.29 | |
// Sale price (bid) of one share of the ETF in EUR | |
const bidPrice = 103.74; | |
// Amount of shares I own in chronologically ascending order. | |
// (first element = oldest shares) | |
const shares = [ | |
// amount, share price at the time in EUR | |
[ 30.000, 81.67], | |
[ 6.147, 81.34], | |
[ 119.000, 83.99] | |
]; | |
let fractionedSharesWarning = 'None of the positions will be fractioned.'; | |
const simulateSale = (numSharesSold) => { | |
// Iterate through elements of shares array | |
let sharesIndex = 0; | |
// Total profit (in EUR) earned when numSharesSold is sold at bidPrice. | |
let totalProfit = 0; | |
// Keep track of how many shares (starting with numSharesSold) we still have to sell. | |
let sharesSold = numSharesSold; | |
while (sharesSold > 0 && sharesIndex < shares.length) { | |
//console.log('--------------------------------------------------------------------'); | |
//console.log('Shares left to sell:', sharesSold); | |
const [originalAmount, originalPrice] = shares[sharesIndex]; | |
let amount = originalAmount; | |
if (amount > sharesSold) { | |
// The position is bigger than the number of shares we still need to sell | |
fractionedSharesWarning = | |
`Warning: The position with ${amount} ` + | |
`shares bought at ${originalPrice} ` + | |
`EUR will be reduced to ${Number((amount - sharesSold).toFixed(3))} shares.\n` + | |
'Following FIFO, your next sale will start with this position.'; | |
amount = sharesSold; | |
} | |
const profit = Number(((amount * bidPrice) - (amount * originalPrice)).toFixed(2)); | |
/* | |
console.log( | |
'Selling', amount, | |
'ETF shares at', bidPrice, | |
'EUR per share results in a profit of', profit, | |
'EUR' | |
); | |
*/ | |
totalProfit += profit; | |
sharesSold -= amount; | |
sharesIndex += 1; | |
} | |
totalProfit = Number(totalProfit.toFixed(2)); | |
//console.log('--------------------------------------------------------------------'); | |
/* | |
console.log( | |
'Total profit:', totalProfit, | |
'EUR for', numSharesSold, | |
'shares sold. Total sale value:', Number((numSharesSold * bidPrice).toFixed(2)) | |
); | |
*/ | |
return totalProfit; | |
}; | |
let numSharesToSell = 0; | |
let profit = 0; | |
while (true) { | |
numSharesToSell += 1; | |
profit = simulateSale(numSharesToSell); | |
if (profit >= optimalProfit) { | |
numSharesToSell -= 1; | |
profit = simulateSale(numSharesToSell); | |
break; | |
} | |
} | |
console.log( | |
'You should sell', numSharesToSell, | |
'shares to approximate but not exceed the optimal profit of', optimalProfit, | |
'EUR with', profit, | |
'EUR.' | |
); | |
console.log(fractionedSharesWarning); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment