Research: Foreign Exchange Handling (Rate Sources, CRA Rules, System Design)
Date of research: 2026-08-05
Method: 4 targeted web searches (Bank of Canada Valet API / noon-rate history, CRA acceptable rates, CRA Folio S5-F4-C1, multi-currency system design).
Purpose: Define where AIR's FX pass gets its rates, which rate the Canadian tax authority accepts, and how the compiler must record FX in the ledger. Complements accounting-standards.md §3 (IAS 21 semantics).
1. Bank of Canada exchange rates and the Valet API
- The historical noon rate (and closing rate) was discontinued: legacy noon/closing rates were last updated 28 April 2017 and are frozen. Since 1 March 2017 the Bank publishes a single daily average exchange rate per currency pair.
- Daily average rates are published once each business day by 16:30 ET, for CAD against ~26 currencies. The Bank also publishes monthly and annual average rates.
- All Bank of Canada rates are indicative — averages of aggregated price quotes from financial institutions, not transactable rates.
- The Valet API is the Bank's free, no-registration web API for all of this data:
- Docs: https://www.bankofcanada.ca/valet/docs
- Example series:
FXUSDCAD(USD→CAD daily average), e.g.GET https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2026-01-01 - Group endpoints exist for all daily FX rates; RSS feeds per series (e.g. https://www.bankofcanada.ca/valet/fx_rss/FXUSDCAD).
AIR design consequences
- Build a rate provider service in the kernel (
kernel/fx) with the Valet API as the primary CAD source; cache observations locally so compilation is deterministic and replayable (a recompilation must use the same stored rate, never a live fetch). - Every converted amount in the provenance graph carries
{rate, series (e.g. FXUSDCAD), rate_date, provider: bank_of_canada_valet, retrieved_at}. - No business-day = no rate: weekends/holidays require an explicit, documented convention (e.g. last published business-day rate) — a policy parameter, not a hard-coded choice.
- Cross rates (e.g. USD→EUR) must be derived through CAD from two BoC series when operating under Canadian tax rules (see §2).
Sources (consulted 2026-08-05):
- Bank of Canada — Daily exchange rates: https://www.bankofcanada.ca/rates/exchange/daily-exchange-rates/
- Bank of Canada — Valet API docs: https://www.bankofcanada.ca/valet/docs
- Bank of Canada — Valet API how-to guide: https://www.bankofcanada.ca/valet-api-how-to/
- Bank of Canada — Legacy noon and closing rates: https://www.bankofcanada.ca/rates/exchange/legacy-noon-and-closing-rates/
- Bank of Canada — Annual average exchange rates: https://www.bankofcanada.ca/rates/exchange/annual-average-exchange-rates/
2. CRA rules: which rate to use
Primary source: Income Tax Folio S5-F4-C1, Income Tax Reporting Currency (CRA).
- Default: convert a foreign amount using the Bank of Canada rate in effect on the day the amount arises (the "relevant spot rate" — day income is received, expense paid, transaction occurs).
- CRA will generally also accept another published rate if it is: widely available, verifiable, from an independent provider, market-recognized, used for financial reporting where applicable, and used consistently year over year.
- Average rates (annual/monthly BoC averages) may be accepted for income items received throughout the year (interest, dividends, employment income, recurring revenue) — but not for capital transactions (purchase/sale of assets or investments), which require the transaction-date rate.
- Where the statutory "relevant spot rate" definition applies (e.g. functional-currency elections under s. 261), the CRA has no discretion to accept anything other than the Bank of Canada rate; for non-CAD ↔ non-CAD conversions, the rate is derived via CAD from the two BoC series.
AIR design consequences
- Rate-selection policy is ALSL policy data, not engine code:
use: transaction_date_rateas the default, with an opt-inannual_averagepolicy scoped to eligible recurring-income event types and jurisdictionCA. The compiler enforces that capital-type events always use the transaction-date rate. - Consistency requirement → the chosen rate source/method must be versioned in the policy and stable across a fiscal year; changing it is a policy-version event that shows up in the audit trail.
Sources (consulted 2026-08-05):
- CRA — Income Tax Folio S5-F4-C1, Income Tax Reporting Currency: https://www.canada.ca/en/revenue-agency/services/tax/technical-information/income-tax/income-tax-folios-index/series-5-international-residency/series-5-international-residency-folio-4-foreign-currency/income-tax-folio-s5-f4-c1-income-tax-reporting-currency.html
- TaxTips.ca — Reporting foreign amounts on a Canadian return: https://www.taxtips.ca/filing/reporting-foreign-transactions.htm
- Bank of Canada — Exchange rates hub: https://www.bankofcanada.ca/rates/exchange/
- Open Government Portal — Daily average FX rates dataset: https://open.canada.ca/data/en/dataset/bb66787c-9509-456d-bd72-5016abdf39c5
3. How accounting systems record FX
Standard multi-currency ledger practice (consistent with IAS 21 / ASC 830):
- Dual-amount recording: every line stores the transaction-currency amount (as invoiced) and the functional-currency amount (converted at the transaction-date spot rate). The functional currency is the currency of the entity's primary economic environment — an entity-level configuration.
- Realized FX gain/loss — arises on settlement: the difference between the functional-currency value at booking and at payment. Example: invoice €10,000 booked at 1.10, collected at 1.12 → realized gain. Posted to a dedicated P&L account (Dr/Cr Realized FX Gain/Loss).
- Unrealized FX gain/loss — arises at period-end revaluation of open monetary balances (unpaid AR/AP, foreign-currency cash, loans): system compares booking rate to closing rate and posts the difference to Unrealized FX Gain/Loss. These are "paper" movements; systems typically reverse them at the next period open or track them cumulatively per open item.
- Separation for reporting: realized and unrealized are kept in separate accounts for clean reporting, tax treatment, and compliance.
AIR design consequences
- AIR
Money={amount: Decimal, currency}; the FX pass (not the LLM, not the event author) produces the functional-currency leg and appends the conversion to the provenance graph (Invoice → FX → Settlement chain, per the SSA-style traceability requirement). - Three deterministic compiler behaviors, matching §3 of
accounting-standards.md:- Booking: spot rate at transaction date (BoC daily average for CA entities).
- Period-end pass: revalue open monetary items at closing rate → unrealized entries, auto-reversal on period open (fits incremental compilation / contra-entry machinery).
- Settlement: compute realized gain/loss against the booked rate, per open item.
- Never floats: rates and amounts are fixed-point decimals; rounding rules (banker's rounding, per-jurisdiction) are documented policy parameters.
- Golden tests: FX purchase booked/paid across a rate move (realized), open FX receivable across a period end (unrealized + reversal), CAD-only path (FX pass is a no-op).
Sources (consulted 2026-08-05):
- Withum — Accounting for Foreign Exchange Transactions: https://www.withum.com/resources/accounting-for-foreign-exchange-transactions/
- Corporate Finance Institute — Foreign Exchange Gain/Loss: https://corporatefinanceinstitute.com/resources/accounting/foreign-exchange-gain-loss/
- Rillet — Multi-Currency Accounting: A Modern Guide: https://www.rillet.com/blog/multi-currency-accounting-guide
- Beancount.io — FX gains and losses: a practical multi-currency guide: https://beancount.io/blog/2026/05/03/foreign-exchange-gain-loss-multi-currency-accounting-small-business-guide
4. Decisions / follow-ups
- D1: Bank of Canada Valet API is the canonical rate source for Canadian entities; rates are fetched once, stored immutably, and replayed on recompilation.
- D2: Rate-selection rules (transaction-date vs average; weekend fallback) live in ALSL policies, versioned; the engine only enforces provenance and the capital-transaction restriction.
- D3: Ledger schema stores transaction-currency and functional-currency amounts on every line, with realized and unrealized FX in separate accounts.
- Follow-up: research rounding rules for GST/QST on converted amounts before implementing the Tax pass × FX pass interaction; research MT940/camt.053 statement currencies for the reconciliation phase.