Investigation: The FX spot conventions against the market
Table of Contents
This page records an investigation made while the story Bring the FX spot conventions onto the market standard was open.
It is a snapshot, not a description of the system. Whatever it concludes that the code must keep doing belongs on the page that owns the subject; cite that page from code, recipes and models, not this one.
1. Context
A person opened a GBP/USD series in ores.web and saw the same rate for several ticks in a row:
Instant Value Source 2026-10-15 21:45:10Z 1.3586 synthetic.bloomberg.gbpusd 2026-10-15 21:45:08Z 1.3586 synthetic.bloomberg.gbpusd 2026-10-15 21:45:06Z 1.3586 synthetic.bloomberg.gbpusd 2026-10-15 21:45:04Z 1.3587 synthetic.bloomberg.gbpusd 2026-10-15 21:45:02Z 1.3587 synthetic.bloomberg.gbpusd 2026-10-15 21:45:00Z 1.3587 synthetic.bloomberg.gbpusd 2026-10-15 21:44:58Z 1.3587 synthetic.bloomberg.gbpusd
The reading was that the FX spot conventions are wrong. The investigation asked two things: do our FX spot conventions agree with the market, and is the spot data our synthetic feeds write realistic. The answer is that the conventions disagree with the market in four places, that one of those is what makes the series look frozen, and that the data behind it is sound.
2. Methodology
Measured the running environment, then read the model and the display path, then researched the market convention against primary sources.
- The environment:
ores_refdata_currency_pair_conventions_tbl,ores_refdata_currencies_tbl.spot_days,ores_synthetic_fx_spot_generation_configs_tblandores_marketdata_market_observations_tblin databaseores_dev_eager_maxwell. - The model and the seed:
ores.refdata.currency_pair_convention.org,ores.refdata.currency.org,projects/ores.sql/populate/refdata/refdata_currency_pair_conventions_seed_populate.sqlandprojects/ores.sql/populate/synthetic/synthetic_feeds_bloomberg_populate.sql. - The display:
projects/ores.web/packages/web/src/market/seriesView.ts. - The market: the ECB reference rates and their SDMX
DECIMALSmetadata, Deutsche Bank's FX4Cash Currency Guide, CLS's T+1 material, the ISDA FX Definitions, CME and CME/EBS market-structure material, the GFXC FX Global Code, the Federal Reserve H.10 release and the BIS Triennial Survey. - GBP/USD realised volatility was derived from ECB daily USD/EUR and GBP/EUR reference rates over 2024-01 to 2026-10.
Environment: worktree eager_maxwell, preset linux-clang-release-ninja, database ores_dev_eager_maxwell, provisioned with the ACME tenant.
3. Paths taken
- The series read as a data fault. The stored values were read at full precision, not as displayed:
1.3590450087953925, with consecutive ticks about 0.00002 apart, near 0.24 pip. The generator is not flat. This path was set aside. - The display was the fault.
seriesView.tsformats every rate through the convention'sdecimal_places, which the seed sets to 4 for a non-JPY pair. A 0.24-pip move is invisible at 4 decimal places, so several ticks round to the same number. This path held. - The convention fields were compared to the market, one by one, across the six pairs held: EUR/USD, GBP/USD, AUD/USD, USD/CAD, USD/CHF and USD/JPY. Four fields disagree, and the field-by-field result is under Conclusions.
- The spot lag was looked for and found elsewhere.
currency_pair_conventionhas no spot-lag column at all.currency.spot_daysexists andcurrency_pair.spot_daysis derived asmax(base, quote); the seed gives USD 1 and CAD 2, so USD/CAD derives to T+2. This path found the largest error.
4. Conclusions
Our conventions are right where they describe the pip and wrong where they describe the quote, the value date and the increment.
| Field | Our value | Verdict | Market value, and the source that owns it |
|---|---|---|---|
pip_factor non-JPY |
0.0001 |
Accurate | 1 pip = 0.0001 |
pip_factor USD/JPY |
0.01 |
Accurate | 1 pip = 0.01 |
decimal_places non-JPY |
4 |
Accurate as the pip, incomplete as a quote | A live major is quoted to 5 decimal places: the pipette is 0.1 pip. The ECB publishes GBP to 5 dp and USD/CAD/CHF/AUD to 4 dp on the same day, so precision is not uniform |
decimal_places USD/JPY |
2 |
Accurate as the pip | A live JPY quote carries 3 |
tick_size |
1 pip |
Wrong for spot | Spot minimum increments are sub-pip and set per venue; the common finest is the pipette, 0.1 pip. Our own model generator default is 0.1, so the seed and the model disagree |
business_day_convention |
ModifiedFollowing |
Accurate | The market-consistent choice for a value date; the model generator default of Following is the outlier |
spot_relative |
true |
Accurate | An FX forward is quoted off the spot date |
end_of_month |
false |
Likely wrong, and not uniform | Standard forward practice preserves month-end; it must stay configurable |
| Spot lag | Not a column; derived max(base, quote) |
Wrong | USD/CAD is T+1; so are USD/TRY, USD/PHP and USD/RUB; every other pair is T+2 |
The largest error is the value date. The seed gives USD spot_days 1 and CAD 2, and the max rule makes USD/CAD settle T+2, where the market settles it T+1. The same rule mis-derives USD/TRY, USD/PHP and USD/RUB. A max-of-legs rule cannot express a pair-level exception, so the lag has to be a first-class per-pair attribute.
The visible error is the quote precision. The rate is stored correctly and moving about 0.24 pip per tick, but decimal_places = 4 prints it at pip precision, so a sub-pip move does not show. This is the whole of the frozen series; a 5-decimal feed changes on most ticks.
The data itself is sound. At 9.5% annual volatility, a GBP/USD 2-second tick has a standard deviation of about 0.32 pip, so roughly 1 pip of movement in 12 seconds is about one standard deviation and not too quiet. Two caveats: the two-component mixture inflates realised variance by 1.75x, so the feed realises about 12.6% rather than the 9.5% it states, and the model annualises on a 365-day clock where the market uses about 252 trading days, which offsets most of that inflation.
Two further divergences are worth confirming rather than fixing blind: the advance_calendar must be the union of the two holiday sets (the joint business-day calendar), and JPY detection keys off the quote currency only, which misses a JPY-base pair.
5. Recommendations
- State the spot lag per pair. Add it to
currency_pair_conventionor tocurrency_pair, seed USD/CAD, USD/TRY, USD/PHP and USD/RUB as T+1 and the rest as T+2, and stop deriving it as the maximum of the two legs. - Separate the pip from the quote. Keep
pip_factoras it is and let the display precision be the market's: five decimals for a non-JPY pair and three for a JPY pair. Update Pip, tick size, and pip factor, which states the pip convention as though it were the quote precision. - Take the tick size down to a fraction of a pip, per venue, matching the model generator's
0.1and removing the seed's1.0. - Decide
end_of_monthdeliberately, rather than defaulting it to false. - Say what the volatility model realises. Either drop the inflating tail component or state the realised volatility on the page that owns the feed.
- Confirm
advance_calendarand the JPY detection before either is relied on.
The findings were checked against the market's own sources, listed under See also.
6. See also
- Story: Bring the FX spot conventions onto the market standard — the story this investigation answers to.
- Pip, tick size, and pip factor — the domain page whose precision claim this investigation corrects.
- ECB reference rates, and the SDMX API whose
DECIMALSmetadata the precision claims rest on: ECB reference rates and ECB SDMX API. - Deutsche Bank, FX4Cash Currency Guide — "Spot for USDCAD is defined as T+1. Spot for all other currency pairs is defined as T+2", and the T+1 pairs.
- CLS, Shaping FX #06: T+1, the FX ecosystem and CLS — spot settles T+2 and is moving to T+1.
- ISDA, FX definitions material — the Business Day Convention and Settlement Date definitions.
- CME Group, FX Product Guide and CME/EBS market structure — the minimum price increment is a venue concept, reduced over time.
- GFXC, FX Global Code — defines the value date and settlement, and leaves the pip and the tick to market practice.
- Federal Reserve, H.10 Foreign Exchange Rates, and BIS, Triennial Survey.