Smart Order Routing with Dijkstra’s Algorithm
Treating fragmented exchanges as a weighted graph to discover the cheapest liquidity routes in real-time
Introduction
Modern electronic markets look less like a single venue and more like an archipelago of exchanges, dark pools, and liquidity providers. Posting or sweeping an order without considering this fragmentation invites higher spread, hidden fees, and slippage.
Smart Order Routers (SORs) aim to solve this by dynamically decomposing one parent order into many child routes across venues. In this article I’ll show how viewing the market as a weighted graph lets us apply Dijkstra’s shortest-path algorithm to find the cheapest path to fill an order, fast enough for real trading.
The Fragmented Marketplace Problem
An order of size must be filled across distinct venues. Each venue quotes:
- Price (best bid/ask)
- Fee or rebate
- Available depth (you may need multiple hops to satisfy the full size)
The naïve strategy, routing everything to the lowest quoted price, ignores rebates, hidden liquidity, and partial fills. We need a framework that captures all costs together.
Modelling Liquidity as a Graph
Define a directed graph where:
- Vertices V are liquidation states: the remaining quantity .
- Edges E represent child fills on a venue. Each edge bears a weight (cost)
Finding the minimum-cost path from to is exactly a shortest-path problem.
Dijkstra’s Algorithm Refresher
Dijkstra’s algorithm finds the shortest paths from a source node to all others in a graph with non-negative weights. Its complexity is
using a binary heap priority queue, fast enough when is small or the quantity discretisation is coarse.
Why Dijkstra Works for SOR
- Non-negative edge weights, prices + fees are never negative.
- Additive costs, total spend is the sum of individual fills.
- Incremental updates, when a quote changes, only a handful of edges are updated; no need to rebuild the whole graph.
Edge Weights in Detail
A realistic cost function blends price, fee, slippage, and latency:
- – estimated impact cost for size
- – round-trip latency to venue
- – trader-defined risk aversion parameters.
By tuning -values the router can pivot between pure cost minimisation and fast execution.
A Minimal Python Sketch
import heapq
from collections import defaultdict
def dijkstra_sor(start_qty, venues):
"""
venues: list of dicts {'name': str, 'price': float, 'fee': float, 'depth': int}
start_qty: int
"""
# state is remaining quantity
dist = defaultdict(lambda: float('inf'))
prev = {}
dist[start_qty] = 0
pq = [(0, start_qty)]
while pq:
cost, qty = heapq.heappop(pq)
if qty == 0:
break # finished
for v in venues:
fill = min(v['depth'], qty)
nxt = qty - fill
w = fill * (v['price'] + v['fee'])
new_cost = cost + w
if new_cost < dist[nxt]:
dist[nxt] = new_cost
prev[nxt] = (qty, v['name'], fill)
heapq.heappush(pq, (new_cost, nxt))
# Reconstruct route
route, node = [], 0
while node in prev:
prev_node, venue, fill = prev[node]
route.append((venue, fill))
node = prev_node
return list(reversed(route)), dist[0]
The sketch ignores slippage and latency penalties, but extending w to the full formula above is one line.
Real-Time Tweaks
- Streaming quotes → treat weight updates as decreases in Dijkstra’s heap; this costs per change.
- Incremental fills → after each child order, update and re-run Dijkstra for the remaining size.
- Failover → if a venue rejects, mark its edges weight and continue; the path automatically reroutes.
Beyond Classic Dijkstra
- -shortest paths for order slicing across the top-k cheapest routes.
- Constrained shortest path where time-to-fill becomes an additional dimension.
- Multi-objective optimisation: Pareto-efficient frontiers via ε-constraint or genetic algorithms when cost and information leakage are both critical.
Complexity Check
With quantity discretised to lots of :
Thus
which is tractable as long as isn’t too fine.
Takeaways
- Model each venue as an edge whose weight equals all-in cost per fill.
- Run Dijkstra to discover the cheapest execution path from full size to zero.
- Update incrementally on quote changes, no full recompute needed.
- Extend with -shortest, latency constraints, or multi-objective scoring for production-grade SORs.
By borrowing a 1950s graph algorithm, we can tame a 2020s marketplace, transforming fragmented liquidity into a coherent, mathematically optimal path. Happy routing 🚀
Disclaimer: This article is educational and not trading advice. Live deployment requires rigorous back-testing, venue-specific rules, and risk controls.