How every figure is worked out
Every number the tracker shows is computed from your own two DeGiro exports plus public daily prices. This page describes each calculation as the code actually performs it, with a small worked example, and ends with what the method cannot do.
The inputs
Two files from DeGiro. Transactions.csv lists every buy and sell: date and time, instrument (by ISIN), quantity, price and DeGiro's own total for the trade, fees included. Account.csv is your cash statement: every deposit, withdrawal, dividend, interest payment, fee and trade settlement, with DeGiro's running balance per currency. Columns are recognised by their contents rather than by position; an export that doesn't match DeGiro's documented layout is rejected with an error naming what was expected and what was found, rather than read half-right.
The account statement is treated as the source of truth for cash: the cash balance, the money you paid in and took out, dividends, interest and fees all come from it. The transactions file is used for share quantities and cost.
Where prices come from
Each instrument needs a ticker to be priced. The tracker suggests one by looking the ISIN up in OpenFIGI (a public identifier index) and, failing that, in Yahoo Finance's search. Every candidate is checked against a live price fetch before it is offered — a ticker that doesn't return prices is never suggested — and you confirm or change each one before the analysis runs.
Daily closing prices and exchange rates come from Yahoo Finance (exchange rates as currency pairs such as EURUSD=X). They are closing prices adjusted for share splits but not for dividends — your dividends already reach your value as cash from the account statement, so a dividend-adjusted price would count them twice. Prices are cached on the server per ticker and refreshed at most once a day. Weekends and holidays carry the last close forward. If an instrument's latest close is more than five days old the app says so rather than presenting a frozen price as today's.
Bonds and options are quoted differently from shares (a bond as a percentage of face value, an option per share for a 100-share contract). Rather than guess, the tracker derives each instrument's scale from DeGiro's own recorded trade values, so a bond quoted at 100 is valued at par, not at 100 times par.
Daily portfolio value
For every calendar day from your first trade to today, the tracker values the portfolio as the sum of each holding (quantity held at the end of that day × that day's close) plus the cash balance in each currency, as DeGiro's statement reports it, converted at that day's rate. This daily series is what every return below is measured on.
- Example. At the end of a day you hold 20 shares closing at €50 and 10 shares closing at $30, with €400 in cash and USD→EUR at 0.92 that day.
- Value = 20 × 50 + 10 × 30 × 0.92 + 400 = 1,000 + 276 + 400 = €1,676.
Time-weighted return (TWR)
The time-weighted return measures how the investments performed, independent of when and how much money you added or took out. It is built from chain-linked daily returns: each day's return is that day's change in value, minus any money that moved in or out that day, divided by the previous day's value; the days are then multiplied together.
In symbols, for day t: rt = (Vt − Ft − Vt−1) / Vt−1, and the cumulative return is (1 + r1) × (1 + r2) × … − 1. A flow is counted on the day it is booked, as part of that day's closing value.
Which cash movements count as “money in or out” (F) matters. Dividends, interest, fees and trades are investment results and stay in. Deposits and withdrawals are netted out, and so is every other bookkeeping entry DeGiro makes that isn't a dividend, interest, fee or trade — payment reservations, cash sweeps, the two legs of a currency conversion — because those move the balance without anything having gained or lost value.
- Example. Day 0: the account is worth €10,000.
- Day 1: worth €10,200, nothing paid in. r1 = (10,200 − 0 − 10,000) / 10,000 = +2.00%.
- Day 2: you deposit €5,000 and the account closes at €15,100. r2 = (15,100 − 5,000 − 10,200) / 10,200 = −0.98%.
- TWR = 1.02 × 0.9902 − 1 = +1.00%. The deposit made the account €5,000 bigger, but it is not counted as a gain.
Two guards keep one bad day from wrecking the chain. A day whose previous value is zero, negative, or below 1% of the highest value the account has reached so far is skipped as a neutral link (a near-empty account makes a percentage meaningless), and a single day's return can't be worse than −100%. The overall figure is also shown annualised: (1 + TWR)365.25 / days − 1.
Money-weighted return (XIRR)
The money-weighted return answers a different question: what steady annual rate would have turned the money you actually paid in, on the dates you paid it, into what you have now? It is the rate that makes the net present value of your deposits, withdrawals and today's value equal to zero.
Deposits count as money you paid out (negative), withdrawals and today's total value as money you got back (positive), each at its own date and converted to the display currency at that date's rate. Time is measured as days ÷ 365 from the first flow. There is no formula for the rate, so it is found numerically: the tracker searches between −99.9999% and +10,000% a year using Brent's root-finding method (via SciPy), pinning the rate down to within a millionth of a percentage point. If no rate in that range balances the flows, or there are fewer than two, no XIRR is shown rather than a made-up one.
- Example. €10,000 deposited on 1 January 2024, another €5,000 on 1 July (day 182), and the account is worth €16,000 on 31 December (day 365).
- Solve −10,000 − 5,000 / (1 + r)182/365 + 16,000 / (1 + r)365/365 = 0.
- r = 8.03% a year. “Gain ÷ deposits” would say 1,000 / 15,000 = 6.7%, understating it because the second €5,000 was only invested for half the year.
The TWR vs XIRR guide shows the two disagreeing on the same account, and why both can be right.
Each calendar year on its own
The year-by-year table is not cut out of the all-time series. Each calendar year's time-weighted return is computed independently: the chain starts fresh from that year's first day, so a strong or weak earlier year can't inflate or dilute a later year's figure. A year with fewer than two days of data is left out.
A partial year — the year you opened the account, or this year so far — is also shown annualised so it can be read beside full years, with the caveat that it rests on less data.
- Example. Your account opened on 1 October 2025 and returned 3.00% by 31 December — 91 days.
- 2025's own return is +3.00%; the by-year view shows it annualised, 1.03365.25/91 − 1 = 12.6%.
- If 2026 then loses 5% from its own 1 January value, 2026 shows about −5% — not the 1.03 × 0.95 − 1 = −2.15% you'd get by reading it off the cumulative line.
Cost basis and profit per position (FIFO)
Trades are replayed in the order DeGiro recorded them. Each buy opens a lot whose cost per share is DeGiro's total for the trade, fees included, divided by the quantity. Each sell uses up the oldest open lots of that same ISIN first — first in, first out — and the realised profit is DeGiro's total for the sale minus the cost of the lots it used up.
Unrealised profit on what you still hold is today's market value minus the cost of the remaining lots, and its percentage is relative to that cost (left blank if the cost is zero).
Viewed in another currency than the one DeGiro booked the trades in, each lot's cost is converted at the rate on the day it was bought and each sale's proceeds at the rate on the day it was sold, so cost and value are always in the same currency and the exchange-rate move since purchase is part of the profit.
- Example. Buy 10 shares for a total of €1,002 (€100.20 each, fee included), later 10 more for €1,202 (€120.20 each).
- Sell 15 for a total of €1,800. FIFO uses all 10 of the first lot (€1,002) and 5 of the second (5 × 120.20 = €601).
- Realised profit = 1,800 − 1,603 = €197. You still hold 5 shares with a cost of €601 (€120.20 each).
Dividends, interest and fees
These are taken straight from the account statement's own entries, grouped by type and totalled, each converted to the display currency at the rate on the day it was booked. They are already part of the daily value (a dividend raises the cash balance, a fee lowers it), so they are reflected in every return above without being added a second time.
Currency: converted at each day's own rate
You can view everything in euros or dollars. Every amount is converted at the exchange rate of its own date — each day's value at that day's rate, each deposit at the rate on the day it was made — never re-priced at today's rate. On a day with no published rate (a weekend), the nearest earlier rate is used.
This is why switching currency changes the returns, not just the symbol: in dollars, the movement of the euro against the dollar becomes part of the result, exactly as it would for an investor who measures their wealth in dollars.
- Example. You deposit $1,000 on a day when one dollar is €0.90, and another $1,000 when it is €0.95.
- In euros those are €900 and €950 — €1,850, not 2,000 × today's rate.
The index comparison
Comparing against an index's quoted yearly return assumes a lump sum on 1 January. Instead, the tracker takes your real deposits and withdrawals, on their real dates and converted to your display currency, and simulates putting that same money into the index: each deposit buys units at that day's price, each withdrawal sells them, and the holding is marked to market daily. Both lines on the chart started from the same money at the same times.
The index is represented by an exchange-traded fund that tracks it, priced in its own currency and converted at each day's rate: SPY for the S&P 500, VWRL for the FTSE All-World and QQQ for the Nasdaq-100. The fund's dividends are reinvested on the day it goes ex-dividend (built from Yahoo's closing prices and dividend payments), because your own dividends count towards your return and the simulated holding has no cash account for its dividends to land in. The fund's own running costs are in its price; no trading fees or taxes — withholding tax on those dividends included — are simulated. The benchmark's year-by-year figures are computed the same independent, per-year way as yours.
- Example. You deposit €1,000 when the fund is at €400 (2.5 units) and another €1,000 when it is at €500 (2 units).
- With the fund at €480, the benchmark account holds 4.5 units worth €2,160 — the figure your own €2,000 is compared against.
Limitations
- Prices are a third party's. Yahoo Finance data can be late, wrong or missing. An instrument with no usable price is left out of the valuation — and its trades are netted out of the time-weighted return so its purchase isn't counted as a loss — and the app lists which instruments that applies to.
- Split-adjusted prices. Yahoo restates past prices for later share splits, so a holding's value before a split is only right if your export records the split as a change in the number of shares you hold.
- Daily resolution. Values are end-of-day; moves within a day are not seen, and money booked on a day is treated as part of that day's close.
- History must be complete. If your export starts after a position was opened, shares sold without a recorded purchase are given a cost of zero, which overstates the realised profit on them.
- FIFO is not your tax rule. Some countries use an average cost or another method for tax; the profit figures here are not a tax calculation.
- It reads the documented export layout. It is built against DeGiro's documented CSV format; an export in a different layout is rejected with an error rather than guessed at.
None of this is investment or tax advice. When a figure matters, check it against DeGiro's own statements — and if one looks wrong, write to jeroemj@gmail.com.