Convert live ticks to the display currency

Python · FastAPI · intermediate · modification

Dashboards were showing raw exchange-local prices; this converts every tick into the display currency before storing it. on_tick now awaits the FX rate and stores the converted quote as self.latest, and get_latest() returns that enriched quote. Verified against the feed by pushing ticks and confirming get_latest() returns the converted price.

A single hot instrument prints ticks in bursts far faster than one FX round-trip; _rates.get_rate() goes over the network with variable latency, so on_tick calls for the same instrument routinely overlap in flight.

Requirements

Files touched

--- app/marketdata/ticker.py
 
 The market-data feed pushes a raw tick for the instrument on every price
-change, and dashboards read the current quote via get_latest().
+change, and dashboards read the current display-currency quote via
+get_latest(). Each tick is enriched before it is stored: the raw price is
+converted into the display currency using the latest FX rate, which is
+fetched over the network. get_latest() then returns that enriched quote.
 """
 
-from app.marketdata.models import Tick
+from app.marketdata.models import Quote, Tick
+from app.marketdata.rates import RatesClient
+
+DISPLAY_CURRENCY = "USD"
 
 
 class PriceTicker:
-    def __init__(self) -> None:
-        self.latest: Tick | None = None
+    def __init__(self, rates: RatesClient) -> None:
+        self._rates = rates
+        self.latest: Quote | None = None
 
-    def on_tick(self, tick: Tick) -> None:
-        self.latest = tick
+    async def _enrich(self, tick: Tick) -> Quote:
+        # Convert the raw price into the display currency. The FX rate is a
+        # network call, so this awaits.
+        rate = await self._rates.get_rate(tick.currency, DISPLAY_CURRENCY)

Review this PR

Python practice