100 shares of Lloyds Bank on LSE, held in a US-based platform with USD as base currency. The holding has to carry four independent value streams — local-currency price, FX rate at a defined snapshot, translated base-currency value, and the hedge-overlay P&L if there's a forward in place — and any two of them disagreeing by more than the snapshot-time tolerance is a reportable break in a back-office reconciliation. Mock data that generates a single "USD value" per holding can't represent the disagreement, which means it can't be used to test the engine that's supposed to detect it.
The rest of this article is the schema and consistency contract: the fields each holding has to carry, the equality and tolerance rules between the four streams, what an FX-consistent synthetic snapshot looks like end-to-end, and the edge cases (illiquid local-market closes, off-cycle FX prints, hedge resets) that mock data has to actually generate to exercise the code path.
The four streams per non-USD holding
Take a UK investor's position in 100 shares of Lloyds Bank (LSE-listed, GBP-denominated) reported by a US wealth-platform with USD as base currency. The position carries:
- Local-currency price. Today's GBP-denominated price per share on LSE.
- FX rate. Today's GBP/USD rate at a defined snapshot time (typically 4pm London or 4pm New York).
- Translated base-currency value. The USD value computed by multiplying local-currency value by the FX rate.
- Hedge-overlay P&L (if hedged). For positions hedged against currency risk, the running P&L on the offsetting FX forward or option position.
// Minimum schema for a non-USD holding (one snapshot)
{
"holding_id": "H-LLOY-2025-09-30",
"symbol": "LLOY",
"exchange": "LSE",
"local_currency": "GBP",
"base_currency": "USD",
"shares": 100,
"local_price": 47.82, // GBP per share
"local_value": 4782.00, // shares × local_price
"fx_rate_local_to_base": 1.2618, // 1 GBP = 1.2618 USD
"fx_rate_snapshot_time": "2025-09-30T16:00:00+01:00",
"base_value": 6033.83, // local_value × fx_rate
"hedge_overlay": {
"hedged": true,
"hedge_instrument": "GBP_USD_FORWARD_3M",
"hedge_notional_base": 6000.00,
"hedge_pnl_base": -47.20 // negative if hedge has unrealized loss
}
}
The minimum schema is not the full schema. Production systems typically also carry: cost basis in both local and base currencies (with the local-currency basis being the customer-experienced figure and the base-currency basis being the IRS-relevant figure for US holders); local-currency vs. base-currency dividend payments separately tracked through the FX timing they were received at; and a hedge-effectiveness ratio for hedged positions where the hedge is a partial offset rather than a full match.
The FX-consistency contract
The single most important property of multi-currency synthetic data is FX consistency: at every snapshot, the base-currency value of every non-USD holding has to equal the local-currency value times the FX rate, to within a small rounding tolerance. The check is mathematically trivial and the most-often-violated property of mock data.
The violations come in three forms:
1. Independent generation of price and FX rate
The most common bug: the synthetic-data tool generates the local-currency price as a random walk and the FX rate as an independent random walk. The base-currency value is computed correctly at each snapshot, but the time series of base-currency returns is uncorrelated across snapshots in ways that don't match real markets. Real GBP/USD has volatility regimes, real LSE prices have correlations with the GBP/USD rate (a falling pound often coincides with rising LSE prices because most large-cap LSE stocks earn substantial dollar revenue), and real cross-rate dynamics are rich.
A test corpus that generates the two independently produces a multi-currency portfolio whose currency-attribution decomposition (what fraction of return came from local-currency price vs. FX vs. interaction) is statistically wrong, not just for any specific holding but for the cross-section. Platforms tested against this kind of data will produce currency-attribution outputs that look plausible and don't match what real customers see.
2. Inconsistent FX rate across snapshots
The bug where snapshot N uses one FX rate timestamp and snapshot N+1 uses a different timestamp, with the result that the implied between-snapshot FX move is partly real and partly artifact. Snapshot timestamps for FX rates have to be calibrated to actual market conventions: WM/Reuters 4pm London for institutional reporting, Federal Reserve 1pm NY for some other contexts. A test corpus that mixes timestamps creates artificial returns that are detectable in any back-test.
3. Missing FX rate during weekend / holiday windows
FX markets are open 24/5; equity markets have holidays. A synthetic dataset that needs an FX rate for a Saturday-close calculation has to either roll forward from Friday close or use a synthetic Saturday rate. Mock-data tools that drop the FX rate on non-trading days produce snapshots with missing translated values; mock-data tools that hallucinate a Saturday rate without specifying its source produce values that don't reconcile against real-world Friday-close anchoring.
Currency attribution — the layered decomposition
Any multi-currency reporting platform has to produce currency attribution: the decomposition of a portfolio's base-currency return into local-currency-return, FX-translation-return, and interaction components. The standard formula:
(1 + R_base) = (1 + R_local) × (1 + R_FX)- R_base
- = base-currency return on the holding
- R_local
- = local-currency return on the holding
- R_FX
- = FX-translation return — appreciation of local currency vs. base
Holding gains 3.12% in GBP; GBP appreciates 1.48% vs USD over the period. R_base = (1.0312)(1.0148) - 1 = 4.65%. The 4.65% decomposes into 3.12% local-currency return + 1.48% FX-translation return + (1.0312 × 1.0148 - 1.0312 - 1.0148 + 1) = 0.05% interaction term.For a portfolio of multiple non-USD holdings, the decomposition extends naturally: portfolio-level base-currency return is the weighted-average decomposition of holding-level returns, with cross-currency exposure aggregated for FX attribution.
The synthetic-data implication: mock data has to include both local-currency and base-currency returns for every non-USD holding at every snapshot. A platform that ingests mock data with only base-currency values cannot exercise the decomposition logic — and the decomposition logic is the part that customers see in reports.
Hedge overlays — when the holding isn't a single thing
A hedged international position is not one holding — it's a long position in the underlying plus a short FX-forward (or FX-option) position offsetting some or all of the currency risk. The total base-currency P&L is the sum of the long position's P&L (translated at current spot) and the FX-forward's P&L (running unrealized gain or loss).
Test data for hedged-position handling has to include:
// Hedged position with overlay
{
"long_position": {
"holding_id": "H-LLOY-LONG",
"shares": 100,
"local_value": 4782.00,
"fx_rate": 1.2618,
"base_value": 6033.83
},
"hedge_position": {
"instrument": "FX_FORWARD",
"currency_pair": "GBPUSD",
"notional": 6000.00, // approximately matches long base value
"forward_rate": 1.2682, // locked at hedge inception
"current_spot": 1.2618,
"days_to_maturity": 47,
"unrealized_pnl_base": -47.20 // small unrealized loss
},
"combined_base_value": 5986.63,
"hedge_effectiveness": 0.9925 // 99.25% of currency risk hedged
}
The hedge-overlay layer has its own consistency rules: the hedge notional should be roughly proportional to the long position's base value, the forward rate at hedge inception was the spot at that moment, and the unrealized P&L on the hedge can be derived from spot vs. forward and time-to-maturity. Mock data that generates hedge positions with arbitrary notionals, forward rates, and unrealized-P&L values won't reconcile against any real hedging logic.
Cost basis in two currencies
US tax treatment of foreign holdings has a subtle but important rule: the gain on sale of a foreign-currency-denominated asset has both a securities component (in local currency) and a currency component (FX translation between purchase date and sale date). For US holders, both components are realized at sale and have to be reported separately on Form 1040.
The synthetic-data shape:
// Foreign holding with dual-currency basis
{
"lot_id": "L-LLOY-2024-03-15-001",
"symbol": "LLOY",
"shares": 100,
"acquisition_date": "2024-03-15",
"local_cost_basis_per_share": 42.18, // GBP at acquisition
"fx_rate_at_acquisition": 1.2741, // GBP/USD on 2024-03-15
"base_cost_basis_per_share": 53.74, // GBP basis × FX
"local_currency": "GBP"
}
On sale, the gain decomposes:
- Securities gain (local currency): (sale price - cost basis) in GBP
- FX gain on the basis itself: Cost basis at sale-date FX rate minus cost basis at acquisition-date FX rate
- FX gain on the securities gain: Realized at sale-date FX rate
For most US holders, the sum of these is what gets reported as capital gain — but the breakdown matters for US tax-form purposes (FX gain has its own sourcing rules), and platforms that report a single base-currency gain without the decomposition produce wrong forms.
What synthetic data has to model
Pulling it together, a realistic multi-currency synthetic test corpus needs:
| Test case | What it exercises | |
|---|---|---|
| Single non-USD holding | Per-holding FX consistency; base-currency translation; cost basis in dual currency | |
| Multi-currency portfolio | Portfolio-level currency attribution; weighted FX exposure aggregation | |
| Hedged international position | Hedge-overlay P&L tracking; effectiveness measurement; spot-vs-forward delta | |
| Currency regime change | FX volatility clustering; correlation-with-equities regime shifts (e.g. 2022 USD strength) | |
| Foreign holding sale with dual-currency gain | Securities gain vs. FX gain decomposition; Form 1040 sourcing | |
| Weekend / holiday FX snapshots | Roll-forward conventions; non-trading-day handling | |
| Cross-rate calculations (non-USD holding for non-USD-base portfolio) | Triangulation through USD; or direct cross-rate availability | |
| Dividend received in foreign currency | Dividend amount at receipt FX vs. dividend amount at translation snapshot |
How this shows up in our catalog
The cross-border bundles in the WealthSynth catalog include households with non-USD holdings (typically 10-30% of asset value in non-USD positions for cross-border-tagged households). The local-currency and FX-rate series are generated jointly via a multi-asset regime-switching model, with regime-conditional cross-correlations between currency pairs and equity returns. Hedged positions are included in the institutional bundles. Cost basis is stored in dual currency for every foreign-currency-denominated lot.
For the broader cross-border context, see Cross-Border & Multi-Currency Wealth. For the tax interaction with foreign withholding, see Treaty-tier withholding and foreign tax credit modeling. For the foreign-fund-specific tax issues, see PFIC tracking and excess-distribution modeling.