SKILL.md
Triangulated FX rates
Most rate feeds list a direct rate to the reporting currency (typically USD). Less liquid currencies are often quoted through a more liquid vehicle currency (commonly EUR or USD itself). On a batch rate tape this is encoded as a second "via" column on the same row:
CCY RATE VIA
USD 1.0000
EUR 1.0850
GBP 1.2750
CHF 0.9200 EUR <-- CHF -> EUR is the first hop
ZAR 0.0650 EUR <-- ZAR -> EUR is the first hop
BRL 0.3000 ZAR <-- BRL -> ZAR -> EUR -> USD : TWO via hops
JPY 0.0064
A blank VIA column means the row is already a direct quote against the
reporting currency. A non-blank VIA column means the row gives the rate
from CCY to VIA — and you still need to convert from VIA to the reporting
currency.
The via chain can be longer than one hop
This is the part that is easy to get wrong. The via currency named on a row is not guaranteed to be a direct quote — it may have its own non-blank via column, which in turn may have another, and so on. A single via lookup is therefore only correct when the via happens to be direct. To get a correct effective rate you must follow the chain: keep multiplying in the next leg's primary rate, moving to that leg's via, until you reach a row whose via is blank (a true direct quote against the reporting currency).
effective_rate(CCY) = primary(CCY) × primary(via(CCY)) × primary(via(via(CCY))) × …
────────────────────────────────────────────────────────────
until the via column is blank (a direct quote)
Worked examples against the table above:
- One hop (CHF): CHF→EUR is 0.9200, EUR is direct (1.0850).
0.9200 × 1.0850 = 0.99820→ 0.9982 (4dp). - Two hops (BRL): BRL→ZAR is 0.3000, ZAR→EUR is 0.0650, EUR is direct
(1.0850).
0.3000 × 0.0650 × 1.0850 = 0.0211575→ 0.0212 (4dp). Stopping after the first via (treating ZAR's 0.0650 as if it were ZAR→USD) gives0.3000 × 0.0650 = 0.0195, wrong by the whole EUR leg.
