SPB Git

spb/air Public MIT

AIR — The Language of Accounting.

Python 100%
8.8 KB · 97 lines markdown
Rendered Raw Blame History
1<!--2Project : AIR — Accounting Intermediate Representation3Author : Simon-Pierre Boucher4Contact : contact@spboucher.ai5File : fx-handling.md6-->78# Research: Foreign Exchange Handling (Rate Sources, CRA Rules, System Design)910**Date of research:** 2026-08-0511**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).12**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).1314---1516## 1. Bank of Canada exchange rates and the Valet API1718- 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.19- 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.20- All Bank of Canada rates are **indicative** — averages of aggregated price quotes from financial institutions, not transactable rates.21- The **Valet API** is the Bank's free, no-registration web API for all of this data:22  - Docs: https://www.bankofcanada.ca/valet/docs23  - Example series: `FXUSDCAD` (USD→CAD daily average), e.g. `GET https://www.bankofcanada.ca/valet/observations/FXUSDCAD/json?start_date=2026-01-01`24  - Group endpoints exist for all daily FX rates; RSS feeds per series (e.g. https://www.bankofcanada.ca/valet/fx_rss/FXUSDCAD).2526### AIR design consequences2728- 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).29- Every converted amount in the provenance graph carries `{rate, series (e.g. FXUSDCAD), rate_date, provider: bank_of_canada_valet, retrieved_at}`.30- **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.31- **Cross rates** (e.g. USD→EUR) must be derived through CAD from two BoC series when operating under Canadian tax rules (see §2).3233Sources (consulted 2026-08-05):34- Bank of Canada — Daily exchange rates: https://www.bankofcanada.ca/rates/exchange/daily-exchange-rates/35- Bank of Canada — Valet API docs: https://www.bankofcanada.ca/valet/docs36- Bank of Canada — Valet API how-to guide: https://www.bankofcanada.ca/valet-api-how-to/37- Bank of Canada — Legacy noon and closing rates: https://www.bankofcanada.ca/rates/exchange/legacy-noon-and-closing-rates/38- Bank of Canada — Annual average exchange rates: https://www.bankofcanada.ca/rates/exchange/annual-average-exchange-rates/3940---4142## 2. CRA rules: which rate to use4344Primary source: **Income Tax Folio S5-F4-C1, Income Tax Reporting Currency** (CRA).4546- 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).47- 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**.48- **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**.49- 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.5051### AIR design consequences5253- Rate-selection policy is **ALSL policy data**, not engine code: `use: transaction_date_rate` as the default, with an opt-in `annual_average` policy scoped to eligible recurring-income event types and jurisdiction `CA`. The compiler enforces that capital-type events always use the transaction-date rate.54- 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.5556Sources (consulted 2026-08-05):57- 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.html58- TaxTips.ca — Reporting foreign amounts on a Canadian return: https://www.taxtips.ca/filing/reporting-foreign-transactions.htm59- Bank of Canada — Exchange rates hub: https://www.bankofcanada.ca/rates/exchange/60- Open Government Portal — Daily average FX rates dataset: https://open.canada.ca/data/en/dataset/bb66787c-9509-456d-bd72-5016abdf39c56162---6364## 3. How accounting systems record FX6566Standard multi-currency ledger practice (consistent with IAS 21 / ASC 830):67681. **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.692. **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).703. **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.714. **Separation for reporting:** realized and unrealized are kept in **separate accounts** for clean reporting, tax treatment, and compliance.7273### AIR design consequences7475- 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).76- Three deterministic compiler behaviors, matching §3 of `accounting-standards.md`:77  - **Booking:** spot rate at transaction date (BoC daily average for CA entities).78  - **Period-end pass:** revalue open monetary items at closing rate → unrealized entries, auto-reversal on period open (fits incremental compilation / contra-entry machinery).79  - **Settlement:** compute realized gain/loss against the booked rate, per open item.80- **Never floats**: rates and amounts are fixed-point decimals; rounding rules (banker's rounding, per-jurisdiction) are documented policy parameters.81- 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).8283Sources (consulted 2026-08-05):84- Withum — Accounting for Foreign Exchange Transactions: https://www.withum.com/resources/accounting-for-foreign-exchange-transactions/85- Corporate Finance Institute — Foreign Exchange Gain/Loss: https://corporatefinanceinstitute.com/resources/accounting/foreign-exchange-gain-loss/86- Rillet — Multi-Currency Accounting: A Modern Guide: https://www.rillet.com/blog/multi-currency-accounting-guide87- 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-guide8889---9091## 4. Decisions / follow-ups9293- **D1:** Bank of Canada **Valet API** is the canonical rate source for Canadian entities; rates are fetched once, stored immutably, and replayed on recompilation.94- **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.95- **D3:** Ledger schema stores transaction-currency and functional-currency amounts on every line, with realized and unrealized FX in separate accounts.96- **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.97