Statistical Arbitrage & Latency Strategies
Read at your own pace. Code execution, quizzes, progress tracking, and the AI tutor are available in the interactive view with JavaScript enabled.
Signals Get Faster
From quoting to exploiting relationships
In Market Making & Liquidity Provision, we built intuition for quoting, inventory, spread, and adverse selection. Now we shift from providing liquidity to finding temporary mispricings.
Two families matter here:
- Statistical arbitrage: trade when related instruments move unusually far apart.
- Latency strategies: act when one venue, feed, or instrument updates before another.
The shared idea is simple: detect an edge, prove it is still fresh, then route through the OMS path you already built.

Stat Arb Intuition
Trade the relationship, not the story
A basic statistical arbitrage setup compares two related instruments, such as:
- Two share classes of the same company
- An ETF and its basket
- Futures and cash index proxy
- Two correlated stocks in the same sector
We watch a spread:
spread = price_A - beta * price_B
If the spread is normally stable but suddenly stretches, we may bet on mean reversion:
spread too high -> short A, buy B
spread too low -> buy A, short B
Important: this is not magic. The edge lives only if costs, latency, fills, and regime changes do not erase it.

Z Score Signal
Normalize the spread
A raw spread is hard to compare across instruments. A z-score tells us how unusual the current spread is relative to recent history:
z = (current_spread - mean_spread) / standard_deviation
A simple rule might be:
-
z > +2: spread is high → short A, buy B -
z < -2: spread is low → buy A, short B -
abs(z) < 0.5: exit or flatten
This example uses small fixed arrays so you can focus on the signal mechanics, not data ingestion.
```cpp
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<double> priceA{100.0, 100.4, 100.2, 100.7, 101.0, 102.4};
std::vector<double> priceB{50.0, 50.1, 50.0, 50.2, 50.4, 50.6};
const double beta = 2.0;
std::vector<double> spreads;
for (size_t i = 0; i < priceA.size(); ++i) {
spreads.push_back(priceA[i] - beta * priceB[i]);
}
// Use all but the latest spread as the historical window.
double sum = 0.0;
for (size_t i = 0; i + 1 < spreads.size(); ++i) sum += spreads[i];
double mean = sum / static_cast<double>(spreads.size() - 1);
double variance = 0.0;
for (size_t i = 0; i + 1 < spreads.size(); ++i) {
double diff = spreads[i] - mean;
variance += diff * diff;
}
variance /= static_cast<double>(spreads.size() - 1);
double stdev = std::sqrt(variance);
double current = spreads.back();
double z = (current - mean) / stdev;
std::cout << "mean spread: " << mean << "\n";
std::cout << "current spread: " << current << "\n";
std::cout << "z-score: " << z << "\n";
if (z > 2.0) {
std::cout << "Signal: SHORT A, BUY B\n";
} else if (z < -2.0) {
std::cout << "Signal: BUY A, SHORT B\n";
} else {
std::cout << "Signal: no entry\n";
}
}
```
Entry Logic Check
A pair strategy sees z = +2.7 for spread = price_A - beta * price_B. Assume the model expects mean reversion and costs are acceptable.
Which action best matches the signal?
Latency Edge
Same idea, tighter clock
Latency strategies exploit the fact that markets do not update everywhere at exactly the same time.
Example pattern:
fast signal venue updates first
↓
related slow venue still shows old quote
↓
strategy checks edge, freshness, fees, limits
↓
OMS sends aggressive order if edge survives
This builds directly on earlier lessons:
- Market Microstructure & Data Feeds: timestamps and sequence numbers tell us what we know and when.
- Market Data Handling & Order Book Reconstruction: the book must be internally consistent.
- Order Management & FIX Integration: a signal is useless unless it becomes a controlled order.

Freshness Gate
Edge must beat time and cost
A latency-sensitive strategy should not trade just because a visible price gap exists. It needs a freshness gate and a cost gate.
Typical checks:
- Is the quote timestamp recent enough?
- Are sequence numbers continuous?
- Is expected edge larger than fees and slippage?
- Is position and order rate within limits?
- Is the venue reachable within the latency budget?
Below, the strategy only trades if the quote is fresh and the net edge is positive.
```cpp
#include <cstdint>
#include <iostream>
#include <string>
struct Quote {
double bid;
double ask;
std::uint64_t exchange_ts_ns;
};
int main() {
Quote fastVenue{100.10, 100.12, 1'000'000'000};
Quote slowVenue{100.00, 100.03, 1'000'000'120};
std::uint64_t now_ns = 1'000'000'180;
std::uint64_t max_age_ns = 200;
double fee_per_share = 0.002;
double slippage_buffer = 0.003;
// If fast bid is above slow ask, buying slow and selling fast may be attractive.
double gross_edge = fastVenue.bid - slowVenue.ask;
double net_edge = gross_edge - fee_per_share - slippage_buffer;
bool slow_quote_fresh = (now_ns - slowVenue.exchange_ts_ns) <= max_age_ns;
bool edge_positive = net_edge > 0.0;
std::cout << "gross edge: " << gross_edge << "\n";
std::cout << "net edge: " << net_edge << "\n";
std::cout << "slow quote fresh: " << (slow_quote_fresh ? "yes" : "no") << "\n";
if (slow_quote_fresh && edge_positive) {
std::cout << "Decision: BUY slow venue, SELL fast venue\n";
} else {
std::cout << "Decision: pass\n";
}
}
```
Timestamp Trap
True or false: if the apparent arbitrage edge is large enough, a latency strategy can safely ignore quote timestamps and sequence quality.
Adverse Selection Again
Fast does not always mean profitable
Latency strategies face a familiar enemy from Market Making & Liquidity Provision: adverse selection.
If you are trying to hit a stale quote, someone else may already be faster. Your order might arrive after the venue updates, or you may only get filled when the trade is bad.
A practical latency strategy often includes:
- Minimum edge: do not trade tiny gaps.
- Maximum quote age: reject stale opportunities.
- Fill probability estimate: avoid edges you rarely capture.
- Cancel logic: pull resting orders when the signal decays.
- Kill switch: stop when rejects, slippage, or losses spike.
The goal is not to be fast in isolation. The goal is to be fast enough with controlled downside.

Name The Metric
In pairs trading, the normalized distance of the current spread from its historical mean is called the ____.
Strategy Checklist
Before a signal becomes an order
Statistical arbitrage and latency strategies both need a disciplined path from model output to execution.
Use this compact checklist:
- Relationship valid? Correlation, hedge ratio, or venue linkage still makes sense.
- Signal strong? Z-score or price gap exceeds the entry threshold.
- Data fresh? Timestamps, sequence numbers, and book state are trustworthy.
- Costs included? Fees, spread, slippage, and rejects are part of the edge.
- Risk bounded? Position, inventory, order rate, and kill-switch rules are active.
- OMS ready? The order state machine can track fills, partials, cancels, and rejects.
Next, we will use replay and simulation to test whether these rules would have survived historical market conditions—without pretending that paper profits are production profits.
