---
title: "FX Spot Microstructure"
book: "Markets II: Rates, FX and Credit"
subject: quant
language: en
chapter: 15
exercises: 8
source: https://one-course.com/books/quant/2/en/chapter/15-fx-spot-microstructure
---

# Chapter 15 — FX Spot Microstructure

On 15 December 2010 a client of a large bank’s electronic FX platform wrote to it: “we have noticed that there were over 300 rejected orders with you today and the reason is ‘NACK’, could you pls have a look at them”. Two days later, with no answer, it wrote again: “We kept receiving top of the book rates from you and hitting your rate, but we got rejected by you 9 times out of 10”. The New York State Department of Financial Services quoted both messages five years later, in the consent order by which Barclays paid USD 150 million, and found no evidence that the bank had ever replied. The rejections came from a practice called [last look](#def-m2-fx-spot-microstructure-lastlook): the bank held each order for a few tens or hundreds of milliseconds and refused it if the price had moved against the bank in the meantime. This chapter is about the machinery of electronic FX spot: how prices are streamed to clients, why the price a client gets depends on who it is, how [last look](#def-m2-fx-spot-microstructure-lastlook) works and what it costs ([Figure 15.1](#fig-m2-fx-spot-microstructure-timeline)), how dealers skew and internalise, and the code of conduct the market wrote for itself.

## 15.1 Streaming prices and tiered liquidity

**Definition 15.1 (Streaming quote, liquidity tier).**

A *streaming quote* is a bid and an ask, for given sizes, that a liquidity provider publishes continuously to a client or a platform and updates many times a second; the client trades by sending a request at a displayed price. A *liquidity tier* is the set of spreads and sizes a provider shows to a group of clients, set by its view of their flow.

Electronic spot FX is mostly traded on streams. A dealer’s pricing engine takes in the [primary venues](https://one-course.com/books/quant/2/en/chapter/14-the-fx-market#def-m2-the-fx-market-venue), other platforms and its own flow, forms a view of the mid, and publishes to each client a price around it: tight for clients whose trades rarely precede price moves, wider for the others, and sometimes wider again when markets are fast. Principal trading firms stream too, directly to banks and on platforms ([Chapter 14](https://one-course.com/books/quant/2/en/chapter/14-the-fx-market#ch-m2-the-fx-market)). A client with access to many streams sees the best bid and ask across them, aggregated, and sends its request to whoever shows the best price.

The dealer’s problem is that a stream is a free option. It shows a price for a few milliseconds, and anyone who knows the market has moved before the stream has caught up can trade on the stale side. The spread is the dealer’s protection against uninformed noise; tiers, [last look](#def-m2-fx-spot-microstructure-lastlook) and skews are its protection against the rest.

## 15.2 Adverse selection

A market maker’s worst clients are those who trade just before the price moves their way, the adverse selection of One Quant Book 1, chapter 1. In FX spot the purest form is latency arbitrage: a fast firm sees the price move on one venue and hits the stale quotes of slower providers elsewhere before they update. A provider measures its clients with [mark-outs](#def-m2-fx-spot-microstructure-markout).

**Definition 15.2 (Mark-out).**

The *mark-out* of a trade at horizon $H$ is the provider’s profit from marking the position at the mid $H$ after the trade: the half-spread earned minus the move of the mid in the client’s favour over $H$. Averaged over a client’s trades at several horizons, from milliseconds to minutes, it measures how informed the client’s flow is.

A client whose trades have [mark-outs](#def-m2-fx-spot-microstructure-markout) close to the half-spread at every horizon is uninformed; its flow is valuable, and it gets the best tier. A client whose [mark-outs](#def-m2-fx-spot-microstructure-markout) turn negative within a second is trading on information the provider did not have; it is shown wider prices, slower confirmations, or nothing.

## 15.3 Last look and hold times

**Definition 15.3 (Last look, hold time, reject rate).**

*Last look* is a practice by which a liquidity provider receiving a trade request at its quoted price has a final opportunity, a short window after the request arrives, to accept or reject it. The *hold time* is the length of that window; the *reject rate* is the share of requests rejected. The price check can be *asymmetric*, rejecting only requests whose price has moved in the client’s favour beyond a threshold, or *symmetric*, rejecting moves beyond it in either direction.

The provider’s argument for [last look](#def-m2-fx-spot-microstructure-lastlook) is that it can quote tighter if it may refuse the trades that arrive on stale prices. The client’s objection is that a rejected request leaves it with the market risk it wanted to shed, at a worse price, and that an asymmetric check lets the provider keep the trades in which the price moved its way and refuse the others.

![The life of a request under last look. The quote reaches the client, the client’s request reaches the provider after a latency, and the provider decides at the end of the hold time whether to trade at the price it quoted. During the hold the provider, not the client, holds the choice. Schematic.](https://one-course.com/images/onecourse/chapters/quant-2/m2-fx-spot-microstructure/fig-b66a0be8eba3.svg)

***Figure 15.1.** The life of a request under [last look](#def-m2-fx-spot-microstructure-lastlook). The quote reaches the client, the client’s request reaches the provider after a latency, and the provider decides at the end of the [hold time](#def-m2-fx-spot-microstructure-lastlook) whether to trade at the price it quoted. During the hold the provider, not the client, holds the choice. Schematic.*

**Proposition 15.4 (What an asymmetric window takes).**

Let the price move in the client’s favour during the [hold time](#def-m2-fx-spot-microstructure-lastlook) $h$ by $X \sim N(0, \sigma^2 h)$, independent of the request, as it is for an uninformed client. An asymmetric check with threshold $\theta$ rejects when $X > \theta$, and the client gives up, per request,

$$
\mathbb{E}\bigl[X\,\mathbf 1\{X > \theta\}\bigr] \;=\; \sigma\sqrt{h}\;\varphi\!\left(\frac{\theta}{\sigma\sqrt h}\right).
$$

A symmetric check rejects $|X| > \theta$ and takes nothing in expectation ([Figure 15.2](#fig-m2-fx-spot-microstructure-tails)).

**Proof.** For $X = sZ$ with $s = \sigma\sqrt h$, $\mathbb{E}[sZ\mathbf 1\{Z > \theta/s\}] =
s\varphi(\theta/s)$. Under the symmetric check the rejected region is symmetric about zero, so the rejected moves average to zero. ∎

![The move of the price during a 100-millisecond hold, for an uninformed request (standard deviation 0.1 basis points), and the requests rejected with a 0.05-basis-point threshold (shaded). The asymmetric check rejects only the right tail, whose mean the client loses; the symmetric one rejects both tails, which cancel. Illustrative.](https://one-course.com/images/onecourse/chapters/quant-2/m2-fx-spot-microstructure/fig-3c4e0d7d3153.svg)

***Figure 15.2.** The move of the price during a 100-millisecond hold, for an uninformed request (standard deviation 0.1 basis points), and the requests rejected with a 0.05-basis-point threshold (shaded). The asymmetric check rejects only the right tail, whose mean the client loses; the symmetric one rejects both tails, which cancel. Illustrative.*

The symmetric check still costs the client something, the fills it loses, but it does not select against it. This is the distinction regulators drew. In the New York order, Barclays had compared the price at the start and at the end of a hold of tens to hundreds of milliseconds and rejected the orders that had become unprofitable to it; it made the check symmetric in September and October 2014, and one platform, with 7% of its volume, stayed asymmetric until August 2015.

![A simulated EURUSD stream with 10% informed requests. Left: reject rates by hold time for informed and uninformed clients under an asymmetric and a symmetric check with the same 0.05 basis-point threshold. Right: the provider’s one-second mark-out per filled request (solid asymmetric, dashed symmetric). Both checks stop most informed requests; only the asymmetric one turns longer holds into more profit, taken from uninformed clients. Illustrative parameters; data: the chapter’s tutorial.](https://one-course.com/images/onecourse/chapters/quant-2/m2-fx-spot-microstructure/fig-7f21805ac23a.svg)

***Figure 15.3.** A simulated EURUSD stream with 10% informed requests. Left: [reject rates](#def-m2-fx-spot-microstructure-lastlook) by [hold time](#def-m2-fx-spot-microstructure-lastlook) for informed and uninformed clients under an asymmetric and a symmetric check with the same 0.05 basis-point threshold. Right: the provider’s one-second [mark-out](#def-m2-fx-spot-microstructure-markout) per filled request (solid asymmetric, dashed symmetric). Both checks stop most informed requests; only the asymmetric one turns longer holds into more profit, taken from uninformed clients. Illustrative parameters; data: the chapter’s tutorial.*

[Figure 15.3](#fig-m2-fx-spot-microstructure-hold) shows both effects on a simulated stream. Informed requests, which arrive after a move of 0.2 basis points the quote has not caught up with, are almost all rejected by either check at short holds. Uninformed requests are rejected more by the symmetric check, which refuses moves either way, but that costs them nothing on average; the asymmetric check rejects fewer of them and its [mark-out](#def-m2-fx-spot-microstructure-markout) rises with the hold, because every extra millisecond gives the price more time to move in the client’s favour and be refused.

**Example 15.5 (The cost of a window).**

With the stream’s volatility, 0.1 basis points over 100 milliseconds, an asymmetric check with a threshold of 0.05 basis points and a 100-millisecond hold takes $0.1\,\varphi(0.5) = 0.0352$ basis points per request from uninformed clients; with no threshold, 0.0399. On USD 2 billion of requests a day this is about USD 7 041 a day, USD 1.76 million over 250 trading days. The symmetric check with the same threshold rejects 62% of the requests and takes nothing on average.

## 15.4 Skewing and internalisation

**Definition 15.6 (Quote skewing).**

*Quote skewing* is moving a stream’s bid and ask together, off the provider’s estimate of the mid, to attract trades that reduce its inventory: a provider long euros lowers both prices so that clients buy euros from it and fewer sell to it ([Figure 15.4](#fig-m2-fx-spot-microstructure-skew)).

A large provider that receives thousands of client requests a minute can internalise much of its risk (One Quant Book 1, chapter 10): a sale by one client is offset by a purchase by another, and only the residual needs to be hedged on a venue. Skewing makes the netting happen sooner, at the cost of a small concession on price, and every hedge the provider does not send to a venue is information it does not reveal. The inventory models behind skews, which trade off expected spread against the risk of holding a position, are those of One Quant Book 1 and of the market-making games of [Chapter 30](https://one-course.com/books/quant/2/en/chapter/30-market-making-games#ch-m2-market-making-games).

![Quote skewing. With no position the provider quotes symmetrically around its mid; long euros, it lowers both prices, so that buyers come to it and sellers go elsewhere; short, it raises them. The spread is unchanged, the centre moves. Schematic.](https://one-course.com/images/onecourse/chapters/quant-2/m2-fx-spot-microstructure/fig-a0f63859073a.svg)

***Figure 15.4.** [Quote skewing](#def-m2-fx-spot-microstructure-skew). With no position the provider quotes symmetrically around its mid; long euros, it lowers both prices, so that buyers come to it and sellers go elsewhere; short, it raises them. The spread is unchanged, the centre moves. Schematic.*

## 15.5 The global code of conduct

**Definition 15.7 (FX Global Code).**

The *FX Global Code* is a set of principles of good practice for the wholesale FX market, maintained by the Global Foreign Exchange Committee of central banks and private-sector participants. It is not law: participants adhere by signing a statement of commitment.

The Code arrived in 2017, two years after the enforcement cases over the fixing of [Chapter 17](https://one-course.com/books/quant/2/en/chapter/17-fixings-and-flows#ch-m2-fixings-and-flows), and [last look](#def-m2-fx-spot-microstructure-lastlook) is among its most argued-over sections. Principle 17, as updated in December 2024, requires providers that use [last look](#def-m2-fx-spot-microstructure-lastlook) to be transparent about it: to say whether and how price changes in either direction affect the decision, how long it takes and why they use it. It defines [last look](#def-m2-fx-spot-microstructure-lastlook) as a risk control, to check that a request is valid and that its price is still consistent with the market, and forbids using it to gather information or to trade on the request during the window, whether by adjusting prices or by hedging. In August 2021 the Committee published templates on which providers disclose their practices.

**Remark 15.8 (What the Code leaves open).**

The Code does not ban asymmetric checks, nor does it set [hold times](#def-m2-fx-spot-microstructure-lastlook). It asks providers to disclose them and clients to read the disclosures; the pressure that remains is competitive. Clients measure their fill ratios, [hold times](#def-m2-fx-spot-microstructure-lastlook) and [mark-outs](#def-m2-fx-spot-microstructure-markout) by provider, as the tutorial does, and route their requests accordingly.

**As of September 2026 — The Code today.**

The [FX Global Code](#def-m2-fx-spot-microstructure-code)’s current text is dated December 2024; its Principle 17 on [last look](#def-m2-fx-spot-microstructure-lastlook) is as summarised above. The Global Foreign Exchange Committee, set up in May 2017 to maintain it, published in August 2021 a guidance paper on [last look](#def-m2-fx-spot-microstructure-lastlook) and standard templates on which liquidity providers disclose their practices. Adherence remains voluntary, by statement of commitment.

## 15.6 Tutorial: last-look transaction-cost analysis

**Goal.** Simulate a stream with informed and uninformed clients, apply asymmetric and symmetric last-look checks, and measure [reject rates](#def-m2-fx-spot-microstructure-lastlook), fill ratios and [mark-outs](#def-m2-fx-spot-microstructure-markout) as a function of the [hold time](#def-m2-fx-spot-microstructure-lastlook). **End state:** [Figure 15.3](#fig-m2-fx-spot-microstructure-hold), [Example 15.5](#ex-m2-fx-spot-microstructure-window) and the numbers of the weekend problem.

1. **The check and the stream**: each request’s move during the hold and after it. `def check (move: float , threshold: float , policy: str ) -> bool : """True if the request is accepted.""" if policy == " none " : return True if policy == " asymmetric " : return move <= threshold return abs (move) <= threshold # symmetric def simulate (n: int , sigma: float , hold: float , threshold: float , policy: str , informed_share: float = 0.0 , edge: float = 0.0 , horizon: float = 1000.0 , seed: int = 1 ) -> list [Request]: rng = random.Random(seed) out = [] for _ in range (n): informed = rng.random() < informed_share jump = edge if informed else 0.0 at_decision = jump + rng.gauss(0.0 , sigma * math.sqrt(hold)) after = at_decision + rng.gauss(0.0 , sigma * math.sqrt(horizon)) out.append(Request(informed, at_decision, after, check(at_decision, threshold, policy))) return out` **Listing 15.1.** The last-look check and a simulated stream of requests. code/firm/lastlook/firm_lastlook.py
2. **The analysis**: fill ratio, [reject rates](#def-m2-fx-spot-microstructure-lastlook) by client type, [mark-out](#def-m2-fx-spot-microstructure-markout), and the closed form of [Proposition 15.4](#prop-m2-fx-spot-microstructure-transfer). `def tca (requests: list [Request], half: float ) -> dict [str , float ]: """Fill ratio, reject rates by client type, and the provider's mark-out per filled request (half-spread earned less the client-favourable move by the horizon), in basis points.""" filled = [r for r in requests if r.accepted] inf = [r for r in requests if r.informed] uninf = [r for r in requests if not r.informed] def reject_rate (rs: list [Request]) -> float : return sum (not r.accepted for r in rs) / len (rs) if rs else 0.0 return {" fill_ratio " : len (filled) / len (requests), " reject_informed " : reject_rate(inf), " reject_uninformed " : reject_rate(uninf), " markout " : sum (half - r.move_after for r in filled) / len (filled) if filled else 0.0 , " client_gain_filled " : sum (r.move_at_decision for r in filled) / len (requests)} def expected_transfer (sigma: float , hold: float , threshold: float , policy: str ) -> float : """Expected client-favourable move given up per request by rejections, uninformed flow: E[move * 1{rejected}] for move ~ N(0, sigma^2 * hold).""" s = sigma * math.sqrt(hold) phi = math.exp(-0.5 * (threshold / s) ** 2 ) / math.sqrt(2 * math.pi) if policy == " asymmetric " : return s * phi # E[X 1{X > t}] return 0.0 # symmetric: the two tails cancel` **Listing 15.2.** Transaction-cost analysis and the expected transfer. code/firm/lastlook/firm_lastlook.py
3. **Run** `lastlook_demo.by_hold` for each policy, `lastlook_demo.window()` and `fig_lastlook.py` .

**What to change next.** Replace the informed clients’ fixed edge by a random one, and find the [hold time](#def-m2-fx-spot-microstructure-lastlook) at which a symmetric check has rejected 90% of them; then plot the uninformed clients’ fill ratio at that hold.

## 15.7 Build: the last-look analyser

**Purpose.** The miniature firm both takes and gives liquidity in FX spot: as a taker it must know what each provider’s [last look](#def-m2-fx-spot-microstructure-lastlook) costs it; as a maker it must be able to show its clients that its own check is symmetric and short.

**Interface.** `check(move, threshold, policy)`; `simulate(n, sigma, hold, threshold, policy, informed_share, edge, horizon, seed)` returning `Request` records; `tca(requests, half)`; `expected_transfer(sigma, hold, threshold, policy)`.

**Rules.** Moves in basis points, positive in the client’s favour; Brownian mid; policies `none`, `asymmetric`, `symmetric`; seeded simulation.

**Acceptance tests.** `code/firm/lastlook/tests/`: the policies’ definitions; no [last look](#def-m2-fx-spot-microstructure-lastlook) fills everything; the simulated asymmetric transfer within 2% of the closed form; informed requests rejected far more often than uninformed ones.

**Stretch.** Read real fill and reject records (a FIX log) and compute each provider’s hold-time distribution and [mark-outs](#def-m2-fx-spot-microstructure-markout); test statistically whether a provider’s rejects depend on the direction of the move.

Sources and further reading

- New York State Department of Financial Services, Consent Order, In the Matter of Barclays Bank PLC, November 2015.
- Global Foreign Exchange Committee, *FX Global Code* , updated December 2024; press release on last-look guidance and disclosure templates, August 2021.
- Bank for International Settlements, *Quarterly Review* , December 2022, box on the fragmented spot market.

## 15.8 Exercises

**Exercise 15.1 ★.**

A provider sells a client EUR 1 million at 1.1464 when the mid is 1.1463. One second later the mid is 1.1465. Give the provider’s one-second [mark-out](#def-m2-fx-spot-microstructure-markout) in dollars and in basis points.

**Solution of Exercise 15.1.**

The provider earned the half-spread, USD 100, and lost the two-pip move of the mid in the client’s favour, USD 200: a [mark-out](#def-m2-fx-spot-microstructure-markout) of $-\text{USD}~100$, or $-0.87$ basis points of the mid.

**Exercise 15.2 ★.**

Give the standard deviation of the price move over holds of 25, 100 and 400 milliseconds at 0.01 basis points per square-root millisecond.

**Solution of Exercise 15.2.**

$0.01\sqrt{h}$: 0.05, 0.1 and 0.2 basis points.

**Exercise 15.3 ★.**

What must a provider that uses [last look](#def-m2-fx-spot-microstructure-lastlook) disclose under Principle 17, and what must it not do during the window?

**Solution of Exercise 15.3.**

Whether, and how, price changes in either direction affect the decision to accept or reject; the expected or typical time taken to decide; and the purpose of [last look](#def-m2-fx-spot-microstructure-lastlook). During the window it must not use the request to gather information with no intention of trading, nor trade on it, by adjusting its prices or hedging.

**Exercise 15.4 ★★.**

Give the transfer per request of an asymmetric check at a 25-millisecond hold and zero threshold, and compare it with the 100-millisecond hold.

**Solution of Exercise 15.4.**

$0.05\,\varphi(0) = 0.0199$ basis points at 25 milliseconds, against 0.0399 at 100: a quarter of the hold, half the cost.

**Exercise 15.5 ★★.**

A provider long EUR 20 million skews its EURUSD stream by 0.1 pip. Which way, and why may this be cheaper than hedging on a [primary venue](https://one-course.com/books/quant/2/en/chapter/14-the-fx-market#def-m2-the-fx-market-venue)?

**Solution of Exercise 15.5.**

Down: it lowers both bid and ask by 0.1 pip, so that clients buying euros come to it and clients selling go elsewhere. It pays a tenth of a pip on the trades it attracts, less than the spread and market impact of selling EUR 20 million on a venue, and reveals nothing to the market.

**Exercise 15.6 ★★.**

Why does a symmetric check reject more uninformed requests than an asymmetric one with the same threshold, yet cost them less?

**Solution of Exercise 15.6.**

It rejects moves beyond the threshold in both directions, twice the region of the asymmetric check. But the rejected moves in the client’s favour are offset by rejected moves against it, which the client would otherwise have had to accept; the asymmetric check keeps those, and refuses only the good ones.

**Exercise 15.7 ★★★.**

*Coding.* From `by_hold`, give the informed and uninformed [reject rates](#def-m2-fx-spot-microstructure-lastlook) at 100 milliseconds under each policy, and the [mark-outs](#def-m2-fx-spot-microstructure-markout).

**Solution of Exercise 15.7.**

At 100 milliseconds: asymmetric, informed 92.68% and uninformed 30.79% rejected, [mark-out](#def-m2-fx-spot-microstructure-markout) 0.4491 basis points; symmetric, informed 93.46% and uninformed 61.76%, [mark-out](#def-m2-fx-spot-microstructure-markout) 0.3991.

**Exercise 15.8 ★★★.**

*Find the flaw.* “Our [reject rate](#def-m2-fx-spot-microstructure-lastlook) is only 5%, so our [last look](#def-m2-fx-spot-microstructure-lastlook) costs our clients nothing.” Correct it.

**Solution of Exercise 15.8.**

The [reject rate](#def-m2-fx-spot-microstructure-lastlook) does not measure what is rejected. An asymmetric check that rejects 5% of requests, all of them those in which the price moved in the client’s favour, still transfers the value of those moves; and a [hold time](#def-m2-fx-spot-microstructure-lastlook) without rejects costs the client the option the provider holds during it. Look at the direction of the moves on rejected and accepted requests, the [hold times](#def-m2-fx-spot-microstructure-lastlook), and the [mark-outs](#def-m2-fx-spot-microstructure-markout), not only at the reject count.

## 15.9 Problem: The Asymmetric Window

**Problem 15.1.**

Weekend problem — what a last-look window takes from a client

An asset manager sends USD 2 billion of EURUSD requests a day to a provider that uses [last look](#def-m2-fx-spot-microstructure-lastlook) with a 100-millisecond hold and a 0.05-basis-point threshold. The mid moves 0.01 basis points per square-root millisecond, the half-spread is 0.4 basis points, and the manager’s flow is uninformed.

**Part I — The window.**

1. Give the standard deviation of the move over the hold.
2. Under an asymmetric check, what share of requests is rejected?
3. Under a symmetric check with the same threshold?
4. Give the transfer per request under each.
5. Give the asymmetric transfer with no threshold.

**Part II — In money.**

6. Give the daily cost of the asymmetric window.
7. Give it over 250 trading days.
8. How does it compare with the half-spread the manager pays?
9. Give the cost with a 25-millisecond hold and no threshold.
10. Why does the cost grow with the square root of the hold?

**Part III — What the manager sees.**

11. Which statistics reveal an asymmetric check?
12. Why is a low [reject rate](#def-m2-fx-spot-microstructure-lastlook) not enough?
13. What should the manager ask the provider, citing the Code?
14. What else does a rejection cost, beyond the transfer?
15. Why might the manager still prefer a provider with [last look](#def-m2-fx-spot-microstructure-lastlook) ?

**Part IV — Judgement.**

16. What did the New York order find wrong with Barclays’s check?
17. Is a symmetric check fair to the client?
18. How does a firm-price, no-last-look stream protect itself instead?
19. State the *named result* : what the asymmetric window takes from the manager each year.
20. In one sentence: what does a last-look window cost a client?

**Solution of Problem 15.1.**

**1.** $0.01\sqrt{100} = 0.1$ basis points. **2.** $1 - \Phi(0.5) = 30.9\%$. **3.** $2(1 - \Phi(0.5)) = 61.7\%$. **4.** Asymmetric, $0.1\,\varphi(0.5) = 0.0352$ basis points; symmetric, zero. **5.** $0.1/\sqrt{2\pi} = 0.0399$ basis points. **6.** $0.0352 \times 10^{-4} \times 2 \times 10^9$, about USD 7 041. **7.** About USD 1.76 million. **8.** The half-spread costs USD 80 000 a day; the window adds 8.8% to it, hidden. **9.** 0.0199 basis points, about USD 3 989 a day. **10.** The move over the hold has a standard deviation proportional to $\sqrt h$, and the transfer is proportional to that standard deviation. **11.** The direction of the price move on rejected requests (all in the client’s favour), the [mark-outs](#def-m2-fx-spot-microstructure-markout) of accepted requests against rejected ones, and [hold times](#def-m2-fx-spot-microstructure-lastlook) that differ by direction. **12.** It counts rejects, not their direction: a small share of rejects, all on favourable moves, is exactly what a costly asymmetric check produces. **13.** Under Principle 17, whether and how price moves in either direction affect acceptance, the typical [hold time](#def-m2-fx-spot-microstructure-lastlook), and the purpose; and confirmation that the request is not used for trading during the window. **14.** The market risk it wanted to shed, left with it at the moment the price moved against it, and the cost of trading again at a worse price. **15.** Its quotes may be tighter or larger, and a symmetric, short, well disclosed check may be worth its lost fills. **16.** That it was applied broadly and indiscriminately, without checking for latency arbitrage, that it rejected only trades unprofitable to the bank, and that clients were given misleading or no explanations. **17.** It takes nothing on average, but it still refuses trades and leaves the client with the risk; its fairness depends on a short hold and on disclosure. **18.** By wider spreads for clients with poor [mark-outs](#def-m2-fx-spot-microstructure-markout), smaller sizes, tiers, faster price updates, and by refusing to stream to toxic flow at all. **19.** Named result: *the asymmetric window* of 100 milliseconds at a 0.05-basis-point threshold takes 0.0352 basis points per request, about USD 1.76 million a year on USD 2 billion of requests a day. **20.** The value of the price moves in its favour that the provider refuses to honour, plus the risk of every rejected trade.

## 15.10 Interview questions

**Interview question 15.1 ★ trader, developer.**

What is [last look](#def-m2-fx-spot-microstructure-lastlook), and why do liquidity providers use it?

**Solution of Interview question 15.1.**

A short window after a trade request arrives during which the provider may accept or reject it at the quoted price. Providers use it to protect streamed prices against stale-price and latency arbitrage, to check credit and validity, and so to quote tighter to everyone; the cost falls on clients whose requests are rejected.

*What the interviewer is looking for: the definition, the protection argument and its cost.*

**Interview question 15.2 ★ researcher, trader.**

How would you tell, from your fills, whether a provider’s [last look](#def-m2-fx-spot-microstructure-lastlook) is asymmetric?

**Solution of Interview question 15.2.**

Record for every request the mid at the request, at the decision and after it. Compare the distribution of the move during the hold for rejected and accepted requests: with a symmetric check, rejects occur on large moves in both directions; with an asymmetric one, only on moves in your favour. Test whether reject probability depends on the sign of the move, and whether [hold times](#def-m2-fx-spot-microstructure-lastlook) differ by direction.

*What the interviewer is looking for: conditioning on the direction of the move.*

**Interview question 15.3 ★★ researcher.**

What is a [mark-out](#def-m2-fx-spot-microstructure-markout), and how do you use [mark-outs](#def-m2-fx-spot-microstructure-markout) to tier clients?

**Solution of Interview question 15.3.**

The provider’s profit on a trade marked at the mid at a later horizon: the half-spread minus the client-favourable move. Averaged by client over horizons from milliseconds to minutes it shows who trades ahead of moves. Tier by it: tight prices for clients with positive [mark-outs](#def-m2-fx-spot-microstructure-markout), wider or slower for the others, re-estimated regularly with confidence intervals.

*What the interviewer is looking for: the definition and a sensible tiering procedure.*

**Interview question 15.4 ★★ trader.**

You are long EUR 50 million from client flow. Do you skew, hedge, or wait?

**Solution of Interview question 15.4.**

It depends on the flow expected and the risk limits. If clients are likely to buy euros soon, skew the price to attract them and internalise; if the position is large against the limit or the market is fast, hedge part of it on a venue or with an execution algorithm. Waiting without a skew is a view on the price, which a market maker should take only deliberately.

*What the interviewer is looking for: inventory, expected flow and limits, not a single rule.*

**Interview question 15.5 ★★ bank, trader.**

What does the [FX Global Code](#def-m2-fx-spot-microstructure-code) require of [last look](#def-m2-fx-spot-microstructure-lastlook), and what does it not require?

**Solution of Interview question 15.5.**

Transparency and disclosure of how [last look](#def-m2-fx-spot-microstructure-lastlook) works, including its symmetry and timing; use only as a validity and price check; no information gathering and no trading on the request during the window. It does not ban asymmetric checks or fix [hold times](#def-m2-fx-spot-microstructure-lastlook), and it is not law: adherence is voluntary, through statements of commitment.

*What the interviewer is looking for: the substance of Principle 17 and its limits.*

**Interview question 15.6 ★★★ developer.**

Design a pricing engine that streams EURUSD to a thousand clients in several tiers and applies a symmetric last-look check, within a latency budget of tens of microseconds.

**Solution of Interview question 15.6.**

One core computes the mid from venue feeds; per-tier spreads and skews are applied in a precomputed table; quotes are published through a fan-out layer with per-client throttles. Requests arrive on a separate path; the check compares the current mid with the mid at the quoted time, stored with each quote identifier, against a symmetric threshold, after a fixed short hold; the decision and its inputs are logged for later analysis. No allocation on the hot path, lock-free queues, and a replay test against recorded market data.

*What the interviewer is looking for: separation of pricing and acceptance paths, symmetric logic, logging for audit.*
