Complete Guide

Multi-Currency & FX Rates

Master global portfolio management with robust multi-currency support. Track funds in their native currencies, aggregate at the portfolio level, and maintain accurate FX rate snapshots for time-travel analysis.

01Multi-Currency Philosophy

Nagare is built from the ground up to handle multi-currency portfolios correctly. Unlike traditional fund forecasting systems that force everything into a single currency at storage time, Nagare preserves the source currency of every transaction and projection, then converts on-the-fly as needed.

The Five-Step Multi-Currency Pattern

1. Store: Always in sourceCurrency (e.g., a EUR fund stores all values in EUR)

2. Calculate: In sourceCurrency (projections stay in native currency)

3. Display: Convert on-the-fly to user preference (e.g., view EUR fund in USD)

4. Aggregate: Convert to reportingCurrency (e.g., portfolio-level metrics in USD)

5. Track: Snapshot FX rates used (for time-travel and audit trails)

Why This Matters

✓ Precision

No rounding errors from repeated conversions. A EUR 100M fund stays EUR 100M, converted only when displayed.

✓ Audit Trail

FX rate snapshots let you answer "What was the portfolio NAV in USD on Q3 2023 using Q3 2023 FX rates?"

✓ Flexibility

View the same portfolio in multiple currencies without data loss. Switch between USD, EUR, GBP, etc.

✓ Global Portfolios

Mix USD, EUR, GBP, JPY, CNY funds in a single portfolio. Aggregate metrics reflect true portfolio value.

02Supported Currencies

Nagare supports 20+ major currencies out of the box:

USD
US Dollar
EUR
Euro
GBP
British Pound
JPY
Japanese Yen
CNY
Chinese Yuan
AUD
Australian Dollar
CAD
Canadian Dollar
CHF
Swiss Franc
SEK
Swedish Krona
NOK
Norwegian Krone
DKK
Danish Krone
SGD
Singapore Dollar
HKD
Hong Kong Dollar
INR
Indian Rupee
KRW
Korean Won
BRL
Brazilian Real
MXN
Mexican Peso
ZAR
South African Rand
NZD
New Zealand Dollar
PLN
Polish Zloty

Need a Currency Not Listed?

New currencies can be added to the Currency enum in the database schema. Contact support or add it yourself in packages/types/src/enums.ts and run migrations.

03Portfolio Configuration

Before tracking multi-currency funds, you need to configure your portfolio's currency settings. This defines how funds are aggregated and displayed.

Key Concepts

Base Currency

The "home currency" of your portfolio. This is typically the currency of your LP base (e.g., USD for US-based funds, EUR for European funds).

baseCurrency: "USD"

Reporting Currency

The currency used for portfolio-level aggregations and reports. Can be different from base currency (e.g., report in EUR even if base is USD).

reportingCurrency: "USD"

Create Portfolio Config via API

POST /api/v1/portfolio-configBRONZE
curl -X POST https://api.nagarehq.com/api/v1/portfolio-config \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "baseCurrency": "USD",
    "reportingCurrency": "USD",
    "allowMultiCurrency": true,
    "defaultFxRateSource": "ECB"
  }'
Response: 201 Created
{
  "portfolioConfigId": "PC-1710518400000-ABC123",
  "baseCurrency": "USD",
  "reportingCurrency": "USD",
  "allowMultiCurrency": true,
  "defaultFxRateSource": "ECB",
  "tenantId": "your-tenant",
  "createdAt": "2024-03-16T10:30:00Z"
}

One Config Per Tenant

Each tenant (organization) has one portfolio configuration. If you need multiple configurations (e.g., different portfolios with different base currencies), use separate tenants.

04Managing FX Rates

FX rates are stored in the FXRate table. Each rate represents the exchange rate from one currency to another on a specific date.

Add FX Rate Manually via API

POST /api/v1/fx-ratesBRONZE
curl -X POST https://api.nagarehq.com/api/v1/fx-rates \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fromCurrency": "EUR",
    "toCurrency": "USD",
    "rate": 1.0875,
    "date": "2024-03-15",
    "source": "ECB"
  }'

Query FX Rates

Retrieve rates for a specific currency pair and date range:

GET /api/v1/fx-ratesSAGE
curl -X GET "https://api.nagarehq.com/api/v1/fx-rates?fromCurrency=EUR&toCurrency=USD&startDate=2024-01-01&endDate=2024-03-31" \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY"
Response: FX Rates List
{
  "rates": [
    {
      "fxRateId": "FX-1",
      "fromCurrency": "EUR",
      "toCurrency": "USD",
      "rate": 1.0850,
      "date": "2024-01-15",
      "source": "ECB"
    },
    {
      "fxRateId": "FX-2",
      "fromCurrency": "EUR",
      "toCurrency": "USD",
      "rate": 1.0875,
      "date": "2024-02-15",
      "source": "ECB"
    },
    {
      "fxRateId": "FX-3",
      "fromCurrency": "EUR",
      "toCurrency": "USD",
      "rate": 1.0900,
      "date": "2024-03-15",
      "source": "ECB"
    }
  ],
  "count": 3
}

Get Latest Rate

For real-time conversions, fetch the most recent rate:

GET /api/v1/fx-rates/latestSAGE
curl -X GET "https://api.nagarehq.com/api/v1/fx-rates/latest?fromCurrency=EUR&toCurrency=USD" \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY"

05Importing ECB Rates

Manually adding FX rates is tedious. Nagare includes a CLI script to bulk-import historical rates from the European Central Bank (ECB), which provides free, reliable daily rates for 40+ currencies.

Run the Import Script

Bash Command
cd apps/api
npx tsx scripts/import-ecb-fx-rates.ts --since 2020-01-01

This script:

  • Fetches daily FX rates from the ECB XML feed
  • Supports all ECB currency pairs (40+ currencies)
  • Handles both historical backfills and incremental updates
  • Skips duplicates (safe to re-run)

Schedule Automatic Updates

For production, schedule the import script to run daily via cron or Cloud Scheduler:

0 6 * * * cd /app && npx tsx scripts/import-ecb-fx-rates.ts --since yesterday

Supported Currencies (ECB)

The ECB provides rates for all major currencies against EUR. Nagare automatically creates inverse pairs (e.g., if ECB provides EUR→USD, Nagare also creates USD→EUR).

USD
GBP
JPY
CHF
AUD
CAD
SEK
NOK
DKK
SGD
HKD
KRW
CNY
INR
BRL
MXN
ZAR
NZD
PLN
CZK
HUF
RON
BGN
HRK
ISK
TRY

06Multi-Currency Funds

Each fund is denominated in a source currency. All fund parameters, transactions, and projections are stored in that currency.

Creating a Fund in EUR

POST /api/v1/fundsBRONZE
curl -X POST https://api.nagarehq.com/api/v1/funds \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fundId": "EUROPEAN-VENTURE-I",
    "fundName": "European Venture Fund I",
    "fundType": "VENTURE_CAPITAL",
    "currency": "EUR",
    "vintage": 2024,
    "parameters": {
      "parameterType": "MASTER",
      "totalCommitment": 100000000,
      "expectedReturn": 2.5,
      "fundLifeYears": 10
    }
  }'

Multi-Currency Portfolio Example

A typical global portfolio might include:

US Growth Fund
Venture Capital
USD
European Venture I
Venture Capital
EUR
UK Buyout Fund III
Buyout
GBP
Asia Growth Partners
Growth Equity
SGD

When calculating a scenario that includes all these funds, Nagare:

  • 1.Projects each fund independently in its source currency
  • 2.Converts all projections to the portfolio's reporting currency (e.g., USD)
  • 3.Aggregates portfolio-level metrics (total NAV, total distributions, etc.)
  • 4.Snapshots the FX rates used for this calculation

07Currency Conversion Logic

Nagare's FX conversion logic is designed for accuracy and auditability.

Conversion Rules

1.Direct Rate Lookup

If a direct rate exists (e.g., EUR→USD), use it directly.

EUR 100M × 1.0875 = USD 108.75M

2.Inverse Rate Calculation

If only the inverse rate exists (e.g., USD→EUR), calculate the reciprocal.

USD 100M ÷ 1.0875 = EUR 91.95M

3.Cross-Rate Calculation

If neither direct nor inverse exists, use a common base (typically USD or EUR).

Example: GBP → JPY
GBP 100M × 1.27 (GBP→USD) = USD 127MUSD 127M × 150 (USD→JPY) = JPY 19,050M

4.Same Currency (No Conversion)

If source and target currencies are the same, return the value unchanged.

USD 100M → USD 100M

Date-Specific Conversions

When converting for a specific date, Nagare looks for the FX rate closest to (but not after) that date:

Example: Convert EUR 10M to USD on 2024-03-15
Lookup FX rate for EUR→USD on 2024-03-151.0875
Convert: EUR 10,000,000 × 1.0875USD 10,875,000

Missing FX Rate Error

If no FX rate exists for the requested date (or earlier), the conversion will fail with an error:"No FX rate found for EUR→USD on or before 2024-03-15"Solution: Import historical FX rates using the ECB import script.

08FX Rate Snapshots

Every calculation in Nagare creates an FX rate snapshot—a record of which FX rates were used to convert currencies. This enables time-travel analysis: "What was our portfolio NAV in Q3 2023 using Q3 2023 FX rates?"

Why Snapshots Matter

✓ Audit Trail

Answer questions like: "Why did our USD-equivalent NAV change? Was it fund performance or FX movements?"

✓ Variance Analysis

Compare current forecast to historical forecast using the same FX rates (eliminates FX noise).

✓ Compliance

Demonstrate which FX rates were used for regulatory reporting at specific dates.

How It Works

  • 1.When a scenario calculation runs, Nagare identifies all currency pairs needed
  • 2.For each pair, it looks up the FX rate as of the calculation date
  • 3.These rates are stored as a JSONB field in the Scenario record
  • 4.Future reads can use the snapshotted rates instead of current rates
Example Snapshot
{
  "scenarioId": "SCN-123",
  "fxSnapshot": {
    "EUR/USD": 1.0875,
    "GBP/USD": 1.2650,
    "JPY/USD": 0.0067,
    "SGD/USD": 0.7420
  },
  "snapshotDate": "2024-03-15"
}

09API Examples

Convert Currency on Demand

POST /api/v1/fx-rates/convertBRONZE
curl -X POST https://api.nagarehq.com/api/v1/fx-rates/convert \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000000,
    "fromCurrency": "EUR",
    "toCurrency": "USD",
    "date": "2024-03-15"
  }'
Response: Conversion Result
{
  "amount": 10000000,
  "fromCurrency": "EUR",
  "toCurrency": "USD",
  "convertedAmount": 10875000,
  "rate": 1.0875,
  "date": "2024-03-15"
}

Batch Convert Multiple Amounts

POST /api/v1/fx-rates/convert-batchBRONZE
curl -X POST https://api.nagarehq.com/api/v1/fx-rates/convert-batch \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversions": [
      {"amount": 10000000, "fromCurrency": "EUR", "toCurrency": "USD"},
      {"amount": 5000000, "fromCurrency": "GBP", "toCurrency": "USD"},
      {"amount": 100000000, "fromCurrency": "JPY", "toCurrency": "USD"}
    ],
    "date": "2024-03-15"
  }'

Delete FX Rate

DELETE /api/v1/fx-rates/:fxRateIdRED
curl -X DELETE https://api.nagarehq.com/api/v1/fx-rates/FX-123 \
  -H "Authorization: Bearer fnd_live_YOUR_API_KEY"

10Best Practices

Import Historical FX Rates First

Before creating multi-currency funds, import at least 2-3 years of historical FX rates. This ensures projections can convert past transactions correctly.

Schedule Daily Rate Updates

Automate the ECB import script to run daily. This keeps your FX rates current without manual intervention. Use a cron job or Cloud Scheduler.

Use Consistent Reporting Currency

Choose one reporting currency for all scenarios and dashboards (usually USD or EUR). Switching reporting currencies makes time-series comparisons difficult.

Always Check FX Snapshots

When reviewing historical scenarios, check the FX snapshot to understand which rates were used. This prevents confusion when comparing old vs new forecasts.

Document Currency Strategy

If your portfolio has a formal FX hedging strategy, document it in scenario descriptions or fund notes. Nagare calculates spot conversions by default (no hedging).

Monitor FX Rate Gaps

Occasionally check for missing FX rates (e.g., weekends, holidays). ECB doesn't publish rates on non-business days, so Nagare uses the most recent rate.

11Troubleshooting

No FX rate found for currency pair

Error: "No FX rate found for EUR→USD on or before 2024-03-15"

Solution: Import FX rates for the required date range using the ECB import script. If the currency pair isn't supported by ECB, manually add rates via the API.

Portfolio totals don't match sum of funds

Cause: FX rate discrepancies (e.g., using spot rate for aggregation vs snapshot rate).

Solution: Ensure all aggregations use the same FX snapshot. Check the fxSnapshot field in the scenario record.

ECB import script fails

Common causes: Network issues, ECB XML endpoint down, invalid date range.

Solution: Check the ECB endpoint is accessible. Verify the date range is valid (not future dates). Re-run with --since flag for specific date.

Currency conversion seems wrong

Check: Are you using the direct rate or inverse? Cross-rate calculations?

Solution: Use the /fx-rates/convert endpoint to test conversions manually. Check the exact rate used via /fx-rates/latest.

Historical scenario shows different USD values than today

Expected behavior: FX rates change over time. If you recalculate an old scenario with today's rates, USD equivalents will differ.

Solution: Use the snapshotted FX rates from the original calculation for apples-to-apples comparison. Check scenario.fxSnapshot.

Ready to Manage Global Portfolios?

With multi-currency support configured, explore Monte Carlo simulations for probabilistic forecasting and portfolio analytics for advanced metrics.