Story: Currency pair support in reference data

Table of Contents

This page documents a story in Sprint 22. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

Goal

ORE Studio treats currencies as first-class reference data, but currency pairs (conventions, quoting, cross rates) are not yet modelled as such. This story is the umbrella for the full currency pair feature: knowledge-base foundation (done), domain model design (done), the ores.codegen.entity implementation of that model, and librarian support so a new party gets a usable set of currency pairs out of the box. It stays open across all of that — it is not a design-only story.

Status

Field Value
State DONE
Parent sprint Sprint 22
Now Nothing.
Waiting on Nothing.
Next None — 3 remaining polish items moved to Sprint 22 snags.
Last touched 2026-07-10

Acceptance

  • [X] A currency pair knowledge document set exists under doc/knowledge/, broken into small self-contained documents (conventions, quoting, cross rates, etc.) rather than one monolith.
  • [X] The knowledge documents are cross-linked via org-roam [[id:...]] links, including to existing relevant documents (e.g. the cross rates matrix).
  • [X] An index document ties the set together for discoverability.
  • [X] The currency pair entity (and supporting currency fields) is modelled with all fields identified in the knowledge cluster, ready to drive ores.codegen.
  • [X] Creating a party (via librarian) results in a usable set of currency pairs being available for it, following the same publish-from-dq pattern used by the synthetic FX foundation.

Tasks

Task State Start End Description
Build knowledge documents for currency pairs DONE   2026-07-04 Turn freeform notes on currency pairs into a set of small, self-contained zettelkasten-style knowledge documents, cross-linked via org-roam links (including to existing docs like the cross rates matrix), with an index document tying them together.
Model the currency pair entity for codegen DONE   2026-07-04 Model the currency pair (and supporting currency) entities with all fields identified in the knowledge cluster (base/quote, spot days, deliverability/NDF, pip factor/tick size, classification, cut code, fixing source, etc.), ready to drive ores.codegen.
Replace is_g11 flag with an extensible currency-group model DONE   2026-07-04 Correct the currency_pair design: is_g11 is a fixed boolean that can't express overlapping desk groupings (Scandies, Antipodeans, commodity currencies, etc.), and G11 membership belongs on the currency, not the pair. Replace it with a many-to-many currency_group lookup + junction, mirroring the existing party_currencies junction pattern.
Add librarian support for currency pairs DONE 2026-07-08 2026-07-08 Extend the DQ librarian so creating a party yields a usable set of currency pairs out of the box, following the same publish-from-dq bundle pattern used for the synthetic FX foundation.
Reconcile currency_pair design with fx_convention DONE   2026-07-04 fx_convention already covers most of currency_pair's ground (spot days, points factor, calendar, business day convention). Fold its extra fields into the currency_pair design and decide the pip_factor vs points_factor representation, ahead of migrating consumers off fx_convention.
Migrate fx_convention consumers to currency_pair and retire it DONE 2026-07-06 2026-07-08 Point ores.ore's conventions_mapper, the Qt CRUD screens, and the CLI registration at currency_pair instead of fx_convention, then drop fx_convention's SQL table, repository, service, Qt files, and CLI wiring.
Split currency_pair into identity and convention entities; finalize field model DONE   2026-07-04 Split the single currency_pair design into a lean currency_pair identity entity and a currency_pair_convention entity for the fx_convention-derived quoting/date-convention fields, mirroring how ORE conceptually separates a pair from its conventions. Produce the final, settled field-by-field model for both, ready for ores.codegen.entity.
Test ORE import/export of FX conventions against currency_pair DONE 2026-07-09 2026-07-09 Verify ORE's conventions.xml <FX> element round-trips correctly through currency_pair after fx_convention is retired: import a real conventions.xml, confirm parsed values match, then export and diff against the original.
Implement currency_pair and currency_pair_convention via ores.codegen.entity DONE 2026-07-06 2026-07-06 All 5 entities modelled, generated (SQL/C++/messaging/Qt), and building cleanly; new flagged_combo Qt facet added for currency-picker flag icons.
Add a generic FK-combo-with-flag-icons facet to ores.codegen.entity ABANDONED   2026-07-10 Moved to Sprint 22 snags — real remaining work, not worth re-carrying the whole story for.
Currency pair flag icons in list are too small DONE 2026-07-08 2026-07-08 The dual-flag icon in the Currency Pairs list's Pair column renders too small; it should be sized to the width of two single-currency flags and the height of one, matching single-flag display elsewhere.
Base/Quote/Settlement Currency columns have no flags DONE   2026-07-08 The Currency Pairs list's Base, Quote, and Settlement Currency columns show plain ISO codes with no flag icon, unlike other currency-bearing columns/screens in the app.
Deliverable column should use a Yes/No badge DONE   2026-07-08 The Currency Pairs list's Deliverable column shows literal true/false text; it should use a Yes/No badge widget, matching the pattern used for book (clever_dijkstra worktree, not yet merged).
Classification column should use a badge DONE   2026-07-08 The Currency Pairs list's Classification column shows plain text (major/minor/exotic/commodity); add a new classification badge widget and use it in the list, matching the badge pattern used for book.
Currency pair detail dialog prompts to save with no changes DONE   2026-07-08 Opening the Currency Pair detail dialog and immediately closing it prompts 'save changes?' even though nothing was edited — the dirty-tracking is falsely triggered, likely by a widget's initial-value-set path marking the form dirty.
Currency pair detail dialog should use badges for classification/deliverable DONE   2026-07-08 The Currency Pair detail dialog shows classification and deliverable as plain text/checkbox; use the same badge widgets as the list view (and as book, clever_dijkstra worktree, not yet merged).
Add Currency Pairs to the main toolbar DONE   2026-07-08 Currency Pairs has no shortcut button on the application's main toolbar, unlike other frequently-used reference data screens.
Add a Currency Pair Conventions toolbar button to the Currency Pairs MDI window DONE   2026-07-08 The Currency Pairs list MDI window's toolbar has no quick way to jump to Currency Pair Conventions; add a toolbar button there.
Currency Pair Conventions list/detail have no flags for the pair DONE   2026-07-08 The Currency Pair Conventions list and detail dialog show the Pair column as plain text (e.g. USD/KWD) with no flags; apply the same base/quote flag treatment used in the Currency Pairs main dialog.
Business Day Convention should be a badge DONE   2026-07-08 Currency Pair Conventions' Business Day Convention column/field renders as plain text; add a new badge widget for it and use it in both the list and detail dialog.
Spot Relative and End of Month should be Yes/No badges DONE   2026-07-08 Currency Pair Conventions' Spot Relative and End of Month columns/fields render as plain true/false text; use the Yes/No badge widget (same as Currency Pairs' Deliverable) in both list and detail.
Add domain-explanation tooltips to Currency and Currency Pair Convention detail fields ABANDONED   2026-07-10 Moved to Sprint 22 snags.
Document currency pairs and conventions in the user manual DONE 2026-07-08 2026-07-10 Add currency pairs and currency pair conventions to the user manual: what they are, how to manage them, and the classification/convention concepts, following the manual's existing chapter structure.
Pair code doesn't recompute when base/quote currency changes DONE 2026-07-08 2026-07-09 Changing Base or Quote Currency in the Currency Pair detail dialog doesn't update pair_code; raises a design question of whether the entity should be keyed by a GUID instead, with duplicate-pair_code prevention.
Creating a Currency Pair with an already-used pair_code silently versions the existing row DONE 2026-07-09 2026-07-09 The insert trigger treats a colliding pair_code as a new version of the existing record (the same create-vs-update-by-natural-key pattern used everywhere in this codebase), not a rejected duplicate. Now that pair_code is derived and immutable, a user picking an already-used base/quote combo in Add mode gets no error and silently overwrites the unrelated existing pair's data.
Rename deliverable flag to non_deliverable (idiomatic FX trading term) DONE 2026-07-09 2026-07-09 currency_pair.deliverable should be renamed to non_deliverable (and the boolean sense inverted) to match the idiomatic FX trading term 'non-deliverable forward' (NDF) – avoids the double-negative confusion of deliverable=false meaning NDF.
pair_code inline flag icon renders tiny regardless of keyFlagIconSize() ABANDONED   2026-07-10 Moved to Sprint 22 snags.
Consider merging currency_pair_convention back into currency_pair DONE 2026-07-09 2026-07-09 With non_deliverable/settlement_currency/fixing_source dropped, currency_pair is down to 4 fields (pair_code, base_currency, quote_currency, classification) – thin enough to reconsider the earlier deliberate split from currency_pair_convention. Needs a pros/cons decision before any migration.
Currency Pair changes never publish NATS events (missing event registrar wiring) DONE 2026-07-09 2026-07-09 currency_pair_event_registrar.cpp/.hpp were never generated and wired into event_registrar.cpp's register_event_mappings(), unlike currency/book/country/etc – so saving a Currency Pair never publishes ores.refdata.currency_pair_changed, and no client (including the one that just saved) gets notified or auto-refreshes.
Capture screenshots for the Currency Pairs manual chapter DONE 2026-07-10 2026-07-10 Test plan and execution checklist for capturing the five screenshot placeholders added in chapter_5b_currency_pairs.org.

Decisions

  • Knowledge-base foundation shipped as six zettels plus a hub note, extending the existing CRM cluster rather than duplicating it (see the first task's * Plan).
  • Currency pair modelled as its own entity (currency_pair), not folded into currency: spot_days and calendars are derived at read time from the two constituent currencies rather than stored redundantly on the pair, to avoid the two copies drifting apart. Five new columns land on currency itself (spot_days, deliverable, day_basis, base_precedence, holiday_calendar); a new currency_pair_classification auxiliary type reuses the existing rounding_type=/=monetary_nature=/=market_tier soft-FK pattern. Full field-by-field design lives in the second task's * Plan; three open questions (calendar/day-count representation, aux-type model type, fixing-source reference) are deferred to the implementation task.
  • Corrected (third task): the initial design put G11 membership on the pair as a boolean is_g11 flag. That's wrong — it's a currency-level property, and desks need overlapping groupings beyond G11 (Scandies, Antipodeans, commodity currencies, …) that a boolean can't express. Replaced with a currency_group auxiliary type plus a many-to-many currency_currency_group_junction, mirroring the existing party_currencies junction pattern. currency.market_tier is unaffected and coexists as the single-valued primary tier alongside the new multi-valued group system.
  • Discovered: ores.refdata.fx_convention already exists, fully implemented, and covers most of currency_pair's ground (spot days, a points_factor reciprocal to our pip_factor, a calendar field, business day convention, spot-relative/end-of-month flags). It exists only to round-trip ORE's conventions.xml <FX> element — no other consumer. Decision: retire it in favour of currency_pair, folding in its extra fields (see the reconciliation task).
  • Split off (calendar): holiday_calendar (on currency) and advance_calendar (folded in from fx_convention, on currency_pair) are both unvalidated free text pointing at an ORE/QuantLib calendar name. Rather than keep them as raw strings, calendar modelling (validated calendar codes, FK relationships, Qt screens) is split off into its own backlog story, Model calendars as proper ORE Studio reference datacurrency_pair keeps a raw-text calendar field only as an interim measure until that story lands and it can be migrated onto a real FK.
  • Split into two entities: currency_pair (identity) and currency_pair_convention (1:1, the fx_convention-derived quoting/ date fields), matching the codebase's existing *_convention entity family rather than bundling both concerns into one entity. See the fourth task's * Plan for the finalized field lists.
  • Split off (cut code): default_cut_code has no domain model anywhere in ORE Studio — same free-text-pointing-at-nothing problem as calendars. Split off into its own backlog story, Model market data cuts as proper ORE Studio reference data. Unlike the calendar field, default_cut_code is dropped from currency_pair entirely rather than kept as interim text — no current consumer needs it, so there's nothing to regress by adding it back as a proper FK once that story lands.
  • Retired fx_convention: ores.ore, the Qt refdata plugin, and the CLI now read/write currency_pair=/=currency_pair_convention directly; all of fx_convention's SQL/C++/Qt/messaging files are deleted, not deprecated. SpotDays round-trips through a mapper-internal transport struct rather than a persisted field, since the file-based ore roundtrip import/export path has no database access and can't derive it from currency at that point. Two gaps left by earlier tasks were closed as a prerequisite: currency_pair's SQL was generated but never wired into the master schema/RLS scripts, and currency.spot_days was modelled but never regenerated — both fixed with C++/SQL-only changes to avoid clashing with the concurrent "Commission: currency" story.

Out of scope

Emacs 29.3 (Org mode 9.6.15)