Skip to content

Conversation

Evernight
Copy link
Contributor

In the current version switching currencies in the UI has no effect on the shape of the line chart because it assumes constant (latest?) conversion between currencies.

If we ccalculate values at date of the datapoint, the currency conversions are also taken into account and results make sense, at least in my charts.

@Evernight Evernight force-pushed the use-date-for-market-conversion branch from c329b1d to 11c4c63 Compare August 26, 2025 20:51
market = market_value_of_inv(p.pricer, p.target_currency, balance, clamp_date)
cost = cost_value_of_inv(p.pricer, p.target_currency, balance)
cash = -inv_to_currency(p.pricer, p.target_currency, cf_balance) # sum of cash flows
cash = -inv_to_currency(p.pricer, p.target_currency, cf_balance, clamp_date) # sum of cash flows
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the line chart will fluctuate due to currency fluctuations, even if the underlying investment stays constant. I guess that's correct, but it's also a bit confusing 🤔

Currently this function returns data points for all dates of (INVESTMENT, CURRENCY) in the price db, and dates of all transactions. If the data points are now also dependent on the target currency, we should also create data points for every entry of (CURRENY, TARGET_CURRENCY) in the price db. Can you add this here:

currency_pairs: set[tuple[str, str]] = set()
for entry in transactions:
for posting in entry.postings:
if posting.meta["category"] is Cat.ASSET and posting.cost:
# ex. (CORP, USD)
currency_pairs.add((posting.units.currency, posting.cost.currency))
def first(x):
return x[0]
# Get dates of transactions and price directives
entry_dates = sorted(
itertools.chain(
((date, None) for pair in currency_pairs for date, _ in get_prices(p.pricer, pair) if date <= end_date),
((entry.date, entry) for entry in transactions), # already filtered above
),
key=first,
)
to the currency_pairs set?

E.g. if CORP is bought in USD, but my target currency is set to EUR, we should also calculate data points for all price entries of USD/EUR.

And please add a unit test in api/portfolio_test.py.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the line chart will fluctuate due to currency fluctuations, even if the underlying investment stays constant. I guess that's correct, but it's also a bit confusing 🤔

That was actually my expectation, the fact that switching between currencies in the interface didn't affect the graph was subjectively more confusing.
"Even if the underlying investment stays constant" asks for a somewhat philosophical question "relative to what" :). But with this change there will still be an option to choose the cost basis currency in the interface and achieve the same-as-previous results I think, at least for investments comprised of the same base currency holdings.

At least for me comparing the graphs using different currencies was interesting/useful. For example, USD has been fluctuating a lot recently and the difference is noticeable. Also I import consumer price index metrics as an approximation for inflation and it's interesting to see returns relative to estimated inflation as well.

If that makes sense, will do requested changes soon.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it makes sense!

Also I import consumer price index metrics as an approximation for inflation and it's interesting to see returns relative to estimated inflation as well.

That's a nice idea! When I get time I'll add it to the example ledger and the screenshots :)

@Evernight Evernight force-pushed the use-date-for-market-conversion branch from 11c4c63 to cd50639 Compare August 27, 2025 22:06
@Evernight
Copy link
Contributor Author

Evernight commented Aug 27, 2025

Had to wrap my head a bit around why cash flows / cost basis dont't have to be reduced at the specific dates of each particular one. I think the following describes this intuition.
UPD: still not 100% sure about this, need to think and try various cases a bit more.

If you had converted currency to invest (e.g. GBP to USD) then the cost basis would be in GBP and changing rates would affect the returns.
But that's not what actually happened, USD were invested and changing rates should not affect the returns calculations.

On the charts (Portolio page) the cost basis line will move around with the currency rate if the target currency is different from the cost basis' currency. Which, I believe, makes sense: at that point the amount in cost currency was worth that much in target currency.

It's like the target currency switch is now used to recalculate points as converted to that currency throughout time, not just taking the latest conversion rate.

@Evernight Evernight force-pushed the use-date-for-market-conversion branch from cd50639 to 381d320 Compare August 27, 2025 22:08
@Evernight Evernight changed the title Use date for market conversion DRAFT: Use date for market conversion Aug 28, 2025
@Evernight Evernight marked this pull request as draft August 28, 2025 17:37
@Evernight Evernight force-pushed the use-date-for-market-conversion branch from 381d320 to 1649c26 Compare August 28, 2025 18:44
@Evernight
Copy link
Contributor Author

It required some thinking on what's the correct approach so here is some more reasoning I used. I wish there was a good reference implementation but I'm not familiar with financial tools that are advanced enough to do something similar...

Cost basis and returns

Definition https://www.investopedia.com/terms/c/costbasis.asp
Cost basis currency is fixed at the moment of stock purchase.

Normal returns (percentages) are not affected by change of the target currency because the cost basis that it's compared against gets converted to the target currency at the same point in time.

TWR

Definition: https://en.wikipedia.org/wiki/Time-weighted_return
When calculating value in target currency at the point in time, how total in-flows basis should be calculated (and, correspondingly, plotted)?
a) convert each in-flow to target currency at the time it happened
b) sum up all in-flows in the base currency(-ies) up to the moment of evaluation, convert at the rate at that point
c) sum up all in-flows at the base currencies, convert at a fixed rate (e.g. latest available)

It seems that a) should be the answer.
The test for TWR was added that makes some reasonable assertions based on TWR definition.

  1. The TWR of the investment should be the same whether it was 500 invested, then another 500 or 1000 invested all at once
  2. The TWR graph will correspond to the capital growth multiplied by the currency conversion rate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants