Currency
Overview
Section titled “Overview”Every monetary value in Formation — purchase price on an investment event, rent on an occupier event, price share on a portfolio — is stored in local currency (the currency the deal was struck in) and converted at read time into your preferred display currency.
Three display currencies are supported: EUR, GBP, USD. The user’s currency preference under Settings selects which one shows in lists and detail views; the local value is always preserved on the record and is the source of truth.
How values are stored
Section titled “How values are stored”Every record with a money field carries:
- The local amount — the value as recorded, in the currency it was originally paid in.
- The local currency type — which currency that local amount is in.
- Three conversion columns —
PurchasePriceEUR,PurchasePriceGBP,PurchasePriceUSD(or their equivalents for rent, etc.) — populated server-side at SaveChanges using the conversion rates effective for the record’s date.
This means a deal struck at £100m in 2019 stores £100m as the local amount and stamps the EUR / USD equivalents using the 2019 exchange rates, not today’s. The values don’t drift as exchange rates move — historical reports stay accurate.
How values display
Section titled “How values display”When you view a record, the display currency is whichever your preference is set to:
- EUR preference →
PurchasePriceEURshows. - GBP preference →
PurchasePriceGBPshows. - USD preference →
PurchasePriceUSDshows.
In every case, the local amount is also available — typically shown in parentheses alongside the converted figure on detail views, or behind a tooltip on list pages.
Self-currency short-circuit
Section titled “Self-currency short-circuit”When your preferred currency happens to match the record’s local currency, the system returns the local amount directly rather than going through the conversion rate. This guards against warehouse data where the self-rate isn’t exactly 1.0 due to rounding, ensuring that a GBP deal viewed in GBP shows exactly what was typed in.
Concretely: a £100m deal in GBP, viewed by a GBP-preference user, shows £100,000,000.00 — not £100,000,123.45 because the warehouse stored the GBP-to-GBP rate as 1.00000123.
How rates are sourced
Section titled “How rates are sourced”Conversion rates live in a separate CurrencyConversion table populated nightly from a warehouse feed. Each row has:
- A currency type.
- An effective date.
- The conversion rates to EUR, GBP, and USD as of that date.
The conversion service looks up the most recent rate on or before the record’s effective date. If you record a deal dated 1 Jan 2020, the conversion uses the rate from the most recent CurrencyConversion row with effective date ≤ 1 Jan 2020. If no rate exists on or before that date, the service falls back to the most recent available rate of any date.
What you see when conversion data is missing
Section titled “What you see when conversion data is missing”If neither path returns a rate (the currency isn’t in the table at all, or has no rate rows), the conversion column comes back as null. The UI then shows:
- The local amount with the local currency symbol — e.g. AUD 50m.
- A subtle dash or em-dash where the converted figure would normally be.
You don’t get a hard error — the value’s just less useful without the conversion.
Resaving doesn’t change historic rates
Section titled “Resaving doesn’t change historic rates”Editing an existing record doesn’t re-stamp the converted columns with today’s rates. The rates are picked using the record’s date, not the save date, so the EUR / GBP / USD columns continue to reflect the value at the time of the deal even if you edit something else on the record later.
If the record’s date itself changes, the conversion is recomputed against the new date — which is correct behaviour for “we misrecorded the date” but worth knowing if you’re editing dates on old deals.
Related rules
Section titled “Related rules”- Investment Events — Purchase Price + Currency coupling rule.
- Occupier Events — rent currency and per-period qualifiers.
- Portfolios — Purchase Price on the portfolio level.
- Units and display — how rent’s currency symbol substitutes into the DisplayFormat template at render time.
Where this lives
Section titled “Where this lives”- Server-side conversion service:
src/services/api/app/app.api/Services/Conversion/CurrencyConversionService.cs - Currency rate model:
src/common/models/Models/CurrencyConversion.cs,CurrencyType.cs - Nightly import job:
src/services/job/currencyimport/ - Frontend preference:
src/services/web/src/lib/preferences/(Format.Currency) - Display components:
src/services/web/src/lib/components/displays/RentValue.svelteand entity-detail panels