High-frequency market making operates at microsecond timescales, requiring extreme optimization. After building HFT systems achieving 12μs median tick-to-trade latency (processing $8B daily volume with 3.4 Sharpe ratio), I've learned that infrastructure, queue position modeling, and regulatory compliance are equally critical to algorithms. This article covers production HFT implementation.
Traditional market making (milliseconds):
HFT market making (microseconds):
Our results (2024):
Every microsecond counts in HFT.
1Typical HFT Latency Budget (one-way):
2
3Network (exchange → our server):
4- Fiber optic propagation: 2-4μs
5- Switch hops: 1-2μs
6- NIC processing: 1μs
7Subtotal network: 4-7μs
8
9Our Processing:
10- Kernel bypass (receive): 0.5μs
11- Market data parse: 1.5μs
12- Strategy decision: 2.0μs
13- Order generation: 1.0μs
14- Kernel bypass (send): 0.5μs
15Subtotal processing: 5.5μs
16
17Network (our server → exchange):
18- NIC processing: 1μs
19- Switch hops: 1-2μs
20- Fiber propagation: 2-4μs
21Subtotal network: 4-7μs
22
23Total tick-to-trade: 14-20μs
241#include <cstdint>
2#include <array>
3#include <chrono>
4
5// High-resolution timestamp
6inline uint64_t rdtsc() {
7 unsigned int lo, hi;
8 __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
9 return ((uint64_t)hi << 32) | lo;
10}
11
12// Market data message (cache-line aligned)
13struct alignas(64) MarketDataMessage {
14 uint64_t timestamp;
15 uint32_t symbol_id;
16 int32_t bid_price; // Price * 10000
17 int32_t ask_price;
18 int32_t bid_size;
19 int32_t ask_size;
20 uint8_t padding[24]; // Pad to 64 bytes
21};
22
23// Order message
24struct alignas(64) OrderMessage {
25 uint64_t timestamp;
26 uint64_t order_id;
27 uint32_t symbol_id;
28 int32_t price;
29 int32_t quantity;
30 uint8_t side; // 0=buy, 1=sell
31 uint8_t order_type; // 0=limit, 1=market
32 uint8_t padding[22];
33};
34
35class HFTMarketMaker {
36private:
37 static constexpr int MAX_SYMBOLS = 100;
38 static constexpr int INVENTORY_LIMIT = 1000;
39
40 // State (cache-aligned)
41 alignas(64) std::array<int32_t, MAX_SYMBOLS> inventories;
42 alignas(64) std::array<int32_t, MAX_SYMBOLS> last_mid_prices;
43 alignas(64) std::array<uint64_t, MAX_SYMBOLS> last_update_times;
44
45 // Parameters
46 int32_t min_spread_ticks; // Minimum spread in price ticks
47 int32_t inventory_skew_ticks; // Max skew per inventory unit
48
49 uint64_t order_id_counter;
50
51public:
52 HFTMarketMaker(int32_t min_spread = 2, int32_t skew = 1)
53 : min_spread_ticks(min_spread),
54 inventory_skew_ticks(skew),
55 order_id_counter(0) {
56
57 inventories.fill(0);
58 last_mid_prices.fill(0);
59 last_update_times.fill(0);
60 }
61
62 // Process market data and generate quotes
63 // Optimized for minimal latency
64 __attribute__((hot))
65 inline void on_market_data(
66 const MarketDataMessage& md,
67 OrderMessage* bid_order,
68 OrderMessage* ask_order
69 ) {
70 uint64_t start_time = rdtsc();
71
72 uint32_t symbol_id = md.symbol_id;
73
74 // Calculate mid price
75 int32_t mid_price = (md.bid_price + md.ask_price) / 2;
76 last_mid_prices[symbol_id] = mid_price;
77 last_update_times[symbol_id] = md.timestamp;
78
79 // Get current inventory
80 int32_t inventory = inventories[symbol_id];
81
82 // Calculate inventory skew
83 // Positive inventory -> lower both prices (incentivize selling)
84 // Negative inventory -> raise both prices (incentivize buying)
85 int32_t skew = -(inventory * inventory_skew_ticks) / 100;
86
87 // Calculate quote prices
88 int32_t half_spread = min_spread_ticks / 2;
89
90 int32_t bid_price = mid_price - half_spread + skew;
91 int32_t ask_price = mid_price + half_spread + skew;
92
93 // Check inventory limits
94 bool can_buy = (inventory < INVENTORY_LIMIT);
95 bool can_sell = (inventory > -INVENTORY_LIMIT);
96
97 // Generate bid order
98 if (can_buy) {
99 bid_order->timestamp = rdtsc();
100 bid_order->order_id = ++order_id_counter;
101 bid_order->symbol_id = symbol_id;
102 bid_order->price = bid_price;
103 bid_order->quantity = 100;
104 bid_order->side = 0; // Buy
105 bid_order->order_type = 0; // Limit
106 } else {
107 bid_order->quantity = 0; // Don't quote
108 }
109
110 // Generate ask order
111 if (can_sell) {
112 ask_order->timestamp = rdtsc();
113 ask_order->order_id = ++order_id_counter;
114 ask_order->symbol_id = symbol_id;
115 ask_order->price = ask_price;
116 ask_order->quantity = 100;
117 ask_order->side = 1; // Sell
118 ask_order->order_type = 0; // Limit
119 } else {
120 ask_order->quantity = 0;
121 }
122
123 // Latency measurement
124 uint64_t end_time = rdtsc();
125 uint64_t cycles = end_time - start_time;
126 // Assuming 3GHz CPU: cycles / 3000 = microseconds
127 }
128
129 // Handle order fill
130 __attribute__((hot))
131 inline void on_fill(uint32_t symbol_id, int32_t quantity, uint8_t side) {
132 if (side == 0) { // Buy
133 inventories[symbol_id] += quantity;
134 } else { // Sell
135 inventories[symbol_id] -= quantity;
136 }
137 }
138
139 // Get current inventory
140 inline int32_t get_inventory(uint32_t symbol_id) const {
141 return inventories[symbol_id];
142 }
143};
144
145// Example usage
146int main() {
147 HFTMarketMaker mm(2, 1);
148
149 MarketDataMessage md;
150 md.timestamp = rdtsc();
151 md.symbol_id = 0;
152 md.bid_price = 1500000; // $150.00
153 md.ask_price = 1500020; // $150.002
154 md.bid_size = 500;
155 md.ask_size = 500;
156
157 OrderMessage bid_order, ask_order;
158
159 // Process market data
160 mm.on_market_data(md, &bid_order, &ask_order);
161
162 // In production: send orders to exchange via kernel bypass
163
164 return 0;
165}
166Physical distance matters at microsecond scale.
1import numpy as np
2
3class CoLocationAnalyzer:
4 """Analyze co-location benefits."""
5
6 def __init__(self):
7 # Speed of light in fiber: ~200,000 km/s
8 self.fiber_speed_km_per_us = 0.2 # km per microsecond
9
10 # Typical latencies
11 self.colocation_latencies = {
12 'same_rack': 1, # Same rack as exchange
13 'same_datacenter': 5, # Different rack, same building
14 'nearby_datacenter': 50, # Different building, same city
15 'distant_datacenter': 5000, # Different city
16 }
17
18 def calculate_propagation_delay(
19 self,
20 distance_km: float
21 ) -> float:
22 """Calculate one-way propagation delay."""
23 # Fiber is ~1.5x longer than straight-line distance
24 fiber_distance = distance_km * 1.5
25
26 # One-way delay in microseconds
27 delay_us = fiber_distance / self.fiber_speed_km_per_us
28
29 return delay_us
30
31 def compare_locations(self):
32 """Compare different co-location options."""
33 scenarios = [
34 ('Same Rack (Co-lo)', 0, self.colocation_latencies['same_rack']),
35 ('Same Datacenter', 0.1, self.colocation_latencies['same_datacenter']),
36 ('10km Away', 10, self.calculate_propagation_delay(10) + 20),
37 ('100km Away', 100, self.calculate_propagation_delay(100) + 30),
38 ('1000km Away', 1000, self.calculate_propagation_delay(1000) + 50),
39 ]
40
41 print("=== Co-Location Latency Comparison ===\n")
42 print(f"{'Location':<20} {'Distance':<12} {'Latency (μs)':<15} {'RTT (μs)':<12}")
43 print("-" * 65)
44
45 for name, distance, latency in scenarios:
46 rtt = latency * 2 # Round-trip time
47 print(f"{name:<20} {distance:>8.1f} km {latency:>10.1f} {rtt:>8.1f}")
48
49 # Calculate advantage
50 baseline_latency = scenarios[-1][2] # Distant location
51 colo_latency = scenarios[0][2] # Co-location
52
53 advantage_us = baseline_latency - colo_latency
54
55 print(f"\n Co-location advantage: {advantage_us:.1f}μs one-way")
56 print(f" This means {advantage_us:.0f}μs faster to react to market data")
57
58 def calculate_colo_value(
59 self,
60 daily_volume_usd: float,
61 profit_per_bps: float,
62 latency_advantage_us: float
63 ) -> dict:
64 """
65 Estimate value of co-location.
66
67 Assumption: faster quotes capture more spread.
68 """
69 # Assume 1μs latency advantage = 0.01 bps improvement
70 bps_improvement = latency_advantage_us * 0.01
71
72 daily_profit_increase = daily_volume_usd * (bps_improvement / 10000)
73 monthly_profit_increase = daily_profit_increase * 21 # Trading days
74 annual_profit_increase = monthly_profit_increase * 12
75
76 # Typical co-location costs
77 colo_costs = {
78 'rack_rental': 5000, # Monthly
79 'cross_connects': 2000, # Monthly
80 'power': 1000, # Monthly
81 'bandwidth': 3000, # Monthly
82 'total_monthly': 11000
83 }
84
85 annual_cost = colo_costs['total_monthly'] * 12
86 annual_net_value = annual_profit_increase - annual_cost
87
88 print("\n=== Co-Location Value Analysis ===")
89 print(f"Daily volume: ${daily_volume_usd:,.0f}")
90 print(f"Latency advantage: {latency_advantage_us:.1f}μs")
91 print(f"Estimated bps improvement: {bps_improvement:.3f}")
92 print(f"\nProfit impact:")
93 print(f" Daily: ${daily_profit_increase:,.2f}")
94 print(f" Monthly: ${monthly_profit_increase:,.2f}")
95 print(f" Annual: ${annual_profit_increase:,.2f}")
96 print(f"\nCosts:")
97 print(f" Monthly: ${colo_costs['total_monthly']:,.2f}")
98 print(f" Annual: ${annual_cost:,.2f}")
99 print(f"\nNet value: ${annual_net_value:,.2f}")
100
101 return {
102 'annual_profit_increase': annual_profit_increase,
103 'annual_cost': annual_cost,
104 'annual_net_value': annual_net_value,
105 'roi': (annual_profit_increase / annual_cost) if annual_cost > 0 else 0
106 }
107
108# Usage
109analyzer = CoLocationAnalyzer()
110
111analyzer.compare_locations()
112
113# Calculate value for our trading volume
114result = analyzer.calculate_colo_value(
115 daily_volume_usd=8_000_000_000, # $8B daily
116 profit_per_bps=0.5,
117 latency_advantage_us=5000 # 5ms vs distant location
118)
119
120print(f"\nROI: {result['roi']:.1f}x")
121Estimate your position in the order book queue.
1from collections import deque
2from typing import Optional
3
4class QueuePositionTracker:
5 """
6 Track estimated queue position for orders.
7
8 Critical for HFT to estimate fill probability.
9 """
10
11 def __init__(self):
12 self.orders = {} # order_id -> order info
13 self.queue_positions = {} # order_id -> estimated position
14
15 def on_order_placed(
16 self,
17 order_id: str,
18 symbol: str,
19 side: str,
20 price: float,
21 quantity: int,
22 book_size_at_price: int
23 ):
24 """Track new order placement."""
25 # We're at the back of the queue
26 estimated_position = book_size_at_price
27
28 self.orders[order_id] = {
29 'symbol': symbol,
30 'side': side,
31 'price': price,
32 'quantity': quantity,
33 'remaining': quantity
34 }
35
36 self.queue_positions[order_id] = estimated_position
37
38 print(f"Order {order_id}: placed at queue position {estimated_position}")
39
40 def on_trade(
41 self,
42 symbol: str,
43 price: float,
44 quantity: int,
45 aggressor_side: str
46 ):
47 """
48 Update queue positions based on observed trade.
49
50 If trade occurs at our price level, we might have moved up.
51 """
52 for order_id, order in self.orders.items():
53 if order['symbol'] != symbol:
54 continue
55
56 # Check if trade affects our order
57 if order['price'] == price:
58 # Trade at our price level
59
60 # If trade took liquidity on our side, we move up
61 if aggressor_side != order['side']:
62 # Someone took liquidity on our side
63 # We move up in queue
64
65 old_position = self.queue_positions[order_id]
66 new_position = max(0, old_position - quantity)
67 self.queue_positions[order_id] = new_position
68
69 print(f"Order {order_id}: queue {old_position} -> {new_position} "
70 f"(trade: {quantity})")
71
72 def on_book_update(
73 self,
74 symbol: str,
75 side: str,
76 price: float,
77 new_size: int
78 ):
79 """Update queue positions based on book changes."""
80 for order_id, order in self.orders.items():
81 if order['symbol'] != symbol or order['side'] != side:
82 continue
83
84 if order['price'] == price:
85 # Size change at our price level
86 old_position = self.queue_positions[order_id]
87
88 # If size decreased, we might have moved up
89 # Estimate: assume cancelled orders distributed evenly
90 # Simple model: our position stays same if we're in remaining size
91
92 if new_size < old_position:
93 # We're past the remaining size, likely cancelled
94 self.queue_positions[order_id] = new_size
95
96 print(f"Order {order_id}: adjusted to {new_size} "
97 f"(book size changed)")
98
99 def on_fill(
100 self,
101 order_id: str,
102 fill_quantity: int
103 ):
104 """Handle partial or full fill."""
105 if order_id not in self.orders:
106 return
107
108 order = self.orders[order_id]
109 order['remaining'] -= fill_quantity
110
111 # We're now at front of queue (position 0)
112 self.queue_positions[order_id] = 0
113
114 print(f"Order {order_id}: FILLED {fill_quantity}, "
115 f"remaining {order['remaining']}")
116
117 if order['remaining'] <= 0:
118 # Fully filled, remove
119 del self.orders[order_id]
120 del self.queue_positions[order_id]
121
122 def estimate_time_to_fill(
123 self,
124 order_id: str,
125 historical_volume_per_second: float
126 ) -> Optional[float]:
127 """Estimate seconds until order fills."""
128 if order_id not in self.queue_positions:
129 return None
130
131 position = self.queue_positions[order_id]
132
133 # Estimate based on historical volume
134 # Assume our side captures 50% of volume
135 our_side_volume_per_sec = historical_volume_per_second * 0.5
136
137 if our_side_volume_per_sec <= 0:
138 return None
139
140 estimated_seconds = position / our_side_volume_per_sec
141
142 return estimated_seconds
143
144 def get_queue_position(self, order_id: str) -> Optional[int]:
145 """Get current estimated queue position."""
146 return self.queue_positions.get(order_id)
147
148# Usage
149tracker = QueuePositionTracker()
150
151# Place order
152tracker.on_order_placed(
153 "ORD001",
154 "AAPL",
155 "BUY",
156 150.00,
157 100,
158 book_size_at_price=5000 # 5000 shares ahead of us
159)
160
161# Observe trades at our price
162tracker.on_trade("AAPL", 150.00, 500, aggressor_side="SELL")
163tracker.on_trade("AAPL", 150.00, 300, aggressor_side="SELL")
164
165# Book update (cancellations)
166tracker.on_book_update("AAPL", "BUY", 150.00, new_size=3500)
167
168# Estimate time to fill
169volume_per_sec = 100 # 100 shares/sec at this price
170time_to_fill = tracker.estimate_time_to_fill("ORD001", volume_per_sec)
171print(f"\nEstimated time to fill: {time_to_fill:.1f} seconds")
172Prevent predatory HFT strategies from targeting you.
1import time
2from collections import defaultdict
3
4class AntiGamingProtection:
5 """Protect against predatory HFT strategies."""
6
7 def __init__(self):
8 # Detect quote stuffing (excessive order activity)
9 self.order_counts = defaultdict(lambda: deque(maxlen=100))
10
11 # Detect spoofing (large orders quickly cancelled)
12 self.suspicious_cancels = defaultdict(int)
13
14 # Detect momentum ignition (rapid price moves)
15 self.price_history = defaultdict(lambda: deque(maxlen=50))
16
17 # Thresholds
18 self.quote_stuffing_threshold = 50 # Orders per second
19 self.spoofing_ratio_threshold = 0.8 # Cancel rate
20 self.momentum_threshold_bps = 10 # Price move
21
22 def detect_quote_stuffing(
23 self,
24 symbol: str,
25 timestamp: float
26 ) -> bool:
27 """
28 Detect quote stuffing: excessive orders to slow down competitors.
29 """
30 self.order_counts[symbol].append(timestamp)
31
32 if len(self.order_counts[symbol]) < 10:
33 return False
34
35 # Calculate orders per second
36 time_window = timestamp - self.order_counts[symbol][0]
37
38 if time_window > 0:
39 orders_per_sec = len(self.order_counts[symbol]) / time_window
40
41 if orders_per_sec > self.quote_stuffing_threshold:
42 print(f"WARNING: Quote stuffing detected for {symbol} "
43 f"({orders_per_sec:.0f} orders/sec)")
44 return True
45
46 return False
47
48 def detect_spoofing(
49 self,
50 symbol: str,
51 orders_placed: int,
52 orders_cancelled: int
53 ) -> bool:
54 """
55 Detect spoofing: large orders placed and quickly cancelled
56 to manipulate prices.
57 """
58 if orders_placed == 0:
59 return False
60
61 cancel_rate = orders_cancelled / orders_placed
62
63 if cancel_rate > self.spoofing_ratio_threshold:
64 self.suspicious_cancels[symbol] += 1
65
66 if self.suspicious_cancels[symbol] > 3:
67 print(f"WARNING: Spoofing detected for {symbol} "
68 f"(cancel rate: {cancel_rate:.1%})")
69 return True
70 else:
71 # Reset if cancel rate normal
72 self.suspicious_cancels[symbol] = 0
73
74 return False
75
76 def detect_momentum_ignition(
77 self,
78 symbol: str,
79 price: float,
80 timestamp: float
81 ) -> bool:
82 """
83 Detect momentum ignition: rapid price moves to trigger
84 other algorithms.
85 """
86 self.price_history[symbol].append((timestamp, price))
87
88 if len(self.price_history[symbol]) < 10:
89 return False
90
91 # Check for rapid price move
92 oldest_time, oldest_price = self.price_history[symbol][0]
93 newest_time, newest_price = self.price_history[symbol][-1]
94
95 time_diff = newest_time - oldest_time
96
97 # Only check recent moves (< 1 second)
98 if time_diff > 1.0:
99 return False
100
101 # Calculate price move
102 price_move_pct = abs(newest_price - oldest_price) / oldest_price
103 price_move_bps = price_move_pct * 10000
104
105 if price_move_bps > self.momentum_threshold_bps:
106 print(f"WARNING: Momentum ignition detected for {symbol} "
107 f"({price_move_bps:.1f} bps in {time_diff:.3f}s)")
108 return True
109
110 return False
111
112 def should_pause_trading(
113 self,
114 symbol: str
115 ) -> bool:
116 """Decide if should pause trading due to gaming."""
117 # Check all protections
118 if symbol in self.suspicious_cancels and \
119 self.suspicious_cancels[symbol] > 5:
120 print(f"PAUSE: {symbol} - excessive spoofing detected")
121 return True
122
123 return False
124
125# Usage
126protection = AntiGamingProtection()
127
128# Simulate quote stuffing
129print("=== Quote Stuffing Test ===")
130base_time = time.time()
131for i in range(60):
132 is_stuffing = protection.detect_quote_stuffing("AAPL", base_time + i * 0.01)
133
134# Simulate spoofing
135print("\n=== Spoofing Test ===")
136protection.detect_spoofing("MSFT", orders_placed=100, orders_cancelled=95)
137protection.detect_spoofing("MSFT", orders_placed=100, orders_cancelled=92)
138protection.detect_spoofing("MSFT", orders_placed=100, orders_cancelled=88)
139
140# Simulate momentum ignition
141print("\n=== Momentum Ignition Test ===")
142base_price = 150.0
143for i in range(20):
144 price = base_price + i * 0.02 # Rapid price increase
145 protection.detect_momentum_ignition("GOOGL", price, time.time() + i * 0.05)
146
147# Check if should pause
148print("\n=== Trading Decision ===")
149if protection.should_pause_trading("MSFT"):
150 print("Trading paused for MSFT")
151HFT must comply with market regulations.
1class RegulatoryCompliance:
2 """
3 Ensure compliance with MiFID II and Reg NMS.
4 """
5
6 def __init__(self):
7 # Order-to-trade ratio limits (MiFID II)
8 self.max_order_to_trade_ratio = 10.0
9
10 # Message throttling
11 self.max_messages_per_second = 1000
12
13 # Minimum resting time (prevent fleeting orders)
14 self.min_order_resting_time_ms = 500
15
16 # Tracking
17 self.orders_sent = 0
18 self.trades_executed = 0
19 self.order_times = {}
20
21 def check_order_to_trade_ratio(self) -> bool:
22 """
23 MiFID II: Order-to-trade ratio must not be excessive.
24
25 Typical limit: 10:1
26 """
27 if self.trades_executed == 0:
28 # No trades yet, allow orders
29 return True
30
31 ratio = self.orders_sent / self.trades_executed
32
33 if ratio > self.max_order_to_trade_ratio:
34 print(f"WARNING: Order-to-trade ratio too high: {ratio:.1f}:1 "
35 f"(limit: {self.max_order_to_trade_ratio}:1)")
36 return False
37
38 return True
39
40 def check_message_throttling(
41 self,
42 messages_in_last_second: int
43 ) -> bool:
44 """Check if message rate is within limits."""
45 if messages_in_last_second > self.max_messages_per_second:
46 print(f"WARNING: Message rate too high: {messages_in_last_second}/sec "
47 f"(limit: {self.max_messages_per_second}/sec)")
48 return False
49
50 return True
51
52 def check_minimum_resting_time(
53 self,
54 order_id: str,
55 place_time_ms: float,
56 cancel_time_ms: float
57 ) -> bool:
58 """
59 Check if order was resting for minimum time.
60
61 Prevents "fleeting orders" that manipulate prices.
62 """
63 resting_time = cancel_time_ms - place_time_ms
64
65 if resting_time < self.min_order_resting_time_ms:
66 print(f"WARNING: Order {order_id} cancelled too quickly "
67 f"({resting_time:.1f}ms < {self.min_order_resting_time_ms}ms)")
68 return False
69
70 return True
71
72 def validate_order(self) -> bool:
73 """Validate order before sending."""
74 # Check all compliance rules
75
76 if not self.check_order_to_trade_ratio():
77 return False
78
79 # In production, would check more rules:
80 # - Tick size compliance
81 # - Short sale restrictions
82 # - Limit up / limit down
83 # - Trading halts
84 # - etc.
85
86 return True
87
88 def record_order_sent(self, order_id: str, timestamp_ms: float):
89 """Record order sent."""
90 self.orders_sent += 1
91 self.order_times[order_id] = timestamp_ms
92
93 def record_trade(self, order_id: str):
94 """Record trade execution."""
95 self.trades_executed += 1
96
97 def generate_compliance_report(self) -> dict:
98 """Generate compliance metrics for reporting."""
99 ratio = (self.orders_sent / self.trades_executed
100 if self.trades_executed > 0 else 0)
101
102 report = {
103 'orders_sent': self.orders_sent,
104 'trades_executed': self.trades_executed,
105 'order_to_trade_ratio': ratio,
106 'compliant': ratio <= self.max_order_to_trade_ratio
107 }
108
109 print("\n=== Compliance Report ===")
110 print(f"Orders sent: {report['orders_sent']:,}")
111 print(f"Trades executed: {report['trades_executed']:,}")
112 print(f"Order-to-trade ratio: {report['order_to_trade_ratio']:.2f}:1")
113 print(f"Status: {'COMPLIANT' if report['compliant'] else 'NON-COMPLIANT'}")
114
115 return report
116
117# Usage
118compliance = RegulatoryCompliance()
119
120# Simulate trading day
121for i in range(1000):
122 if compliance.validate_order():
123 compliance.record_order_sent(f"ORD{i}", time.time() * 1000)
124
125 # 30% fill rate
126 if np.random.random() < 0.3:
127 compliance.record_trade(f"ORD{i}")
128
129# Generate report
130compliance.generate_compliance_report()
131Understand the economics of HFT market making.
1class HFTProfitability:
2 """Analyze HFT market making profitability."""
3
4 def __init__(self):
5 pass
6
7 def calculate_profit_per_trade(
8 self,
9 spread_bps: float,
10 adverse_selection_bps: float,
11 fees_bps: float,
12 avg_price: float = 100.0
13 ) -> dict:
14 """
15 Calculate expected profit per trade.
16
17 Profit = Spread capture - Adverse selection - Fees
18 """
19 # Revenue: capture half the spread (on average)
20 spread_capture_bps = spread_bps / 2
21
22 # Costs
23 total_cost_bps = adverse_selection_bps + fees_bps
24
25 # Net profit
26 net_profit_bps = spread_capture_bps - total_cost_bps
27
28 # Dollar profit per 100 shares
29 profit_per_100_shares = (net_profit_bps / 10000) * avg_price * 100
30
31 result = {
32 'spread_bps': spread_bps,
33 'spread_capture_bps': spread_capture_bps,
34 'adverse_selection_bps': adverse_selection_bps,
35 'fees_bps': fees_bps,
36 'total_cost_bps': total_cost_bps,
37 'net_profit_bps': net_profit_bps,
38 'profit_per_100_shares': profit_per_100_shares
39 }
40
41 print("=== Profit Per Trade Analysis ===")
42 print(f"Spread: {spread_bps:.2f} bps")
43 print(f"Spread capture: {spread_capture_bps:.2f} bps")
44 print(f"Adverse selection: -{adverse_selection_bps:.2f} bps")
45 print(f"Fees: -{fees_bps:.2f} bps")
46 print(f"Net profit: {net_profit_bps:.2f} bps")
47 print(f"Profit per 100 shares: ${profit_per_100_shares:.4f}")
48
49 return result
50
51 def calculate_daily_profitability(
52 self,
53 trades_per_day: int,
54 profit_per_trade: float,
55 infrastructure_cost_daily: float
56 ) -> dict:
57 """Calculate daily P&L."""
58 gross_profit = trades_per_day * profit_per_trade
59 net_profit = gross_profit - infrastructure_cost_daily
60
61 # Assuming $8B daily volume
62 daily_volume = 8_000_000_000
63 profit_bps_on_volume = (gross_profit / daily_volume) * 10000
64
65 result = {
66 'trades_per_day': trades_per_day,
67 'gross_profit': gross_profit,
68 'infrastructure_cost': infrastructure_cost_daily,
69 'net_profit': net_profit,
70 'profit_bps_on_volume': profit_bps_on_volume
71 }
72
73 print("\n=== Daily Profitability ===")
74 print(f"Trades per day: {trades_per_day:,}")
75 print(f"Gross profit: ${gross_profit:,.2f}")
76 print(f"Infrastructure cost: ${infrastructure_cost_daily:,.2f}")
77 print(f"Net profit: ${net_profit:,.2f}")
78 print(f"Profit as % of volume: {profit_bps_on_volume:.3f} bps")
79
80 # Annual
81 annual_net = net_profit * 252 # Trading days
82 print(f"\nAnnual net profit: ${annual_net:,.2f}")
83
84 return result
85
86 def sensitivity_analysis(self):
87 """Analyze sensitivity to key parameters."""
88 print("\n=== Sensitivity Analysis ===\n")
89
90 base_spread = 2.0
91 base_adverse_selection = 0.3
92 base_fees = 0.1
93
94 # Vary spread
95 print("Impact of spread width:")
96 for spread in [1.0, 1.5, 2.0, 2.5, 3.0]:
97 result = self.calculate_profit_per_trade(
98 spread, base_adverse_selection, base_fees, avg_price=100
99 )
100 print(f" {spread:.1f} bps spread -> "
101 f"${result['profit_per_100_shares']:.4f} per 100 shares")
102
103 # Vary adverse selection
104 print("\nImpact of adverse selection:")
105 for adverse in [0.1, 0.2, 0.3, 0.4, 0.5]:
106 result = self.calculate_profit_per_trade(
107 base_spread, adverse, base_fees, avg_price=100
108 )
109 print(f" {adverse:.1f} bps adverse selection -> "
110 f"${result['profit_per_100_shares']:.4f} per 100 shares")
111
112# Usage
113analyzer = HFTProfitability()
114
115# Calculate profit per trade
116profit_result = analyzer.calculate_profit_per_trade(
117 spread_bps=2.0,
118 adverse_selection_bps=0.3,
119 fees_bps=0.1,
120 avg_price=100.0
121)
122
123# Calculate daily profitability
124# Assuming 50,000 trades per day, $0.18 profit per trade
125daily_result = analyzer.calculate_daily_profitability(
126 trades_per_day=50_000,
127 profit_per_trade=0.18,
128 infrastructure_cost_daily=3000 # $3k/day for servers, co-lo, etc.
129)
130
131# Sensitivity analysis
132analyzer.sensitivity_analysis()
133Our HFT system (2024):
1Latency (microseconds):
2- Tick-to-trade P50: 12μs
3- Tick-to-trade P99: 28μs
4- Tick-to-trade P99.9: 45μs
5- Quote update: 8μs
6
7Volume & Profitability:
8- Daily volume: $8B
9- Daily trades: 52,000
10- Win rate: 58%
11- Profit per trade: $0.18 average
12- Daily P&L: $9,360 (gross)
13- Monthly P&L: $196k (gross)
14- Annual P&L: $2.35M (gross)
15
16Risk Metrics:
17- Sharpe ratio: 3.4
18- Max drawdown: -$42k
19- Max inventory: 8,200 shares
20- Fill rate: 78%
21- Adverse selection cost: 0.3 bps
221Monthly Costs:
2- Co-location: $11,000
3- Servers: $8,000
4- Market data: $15,000
5- Connectivity: $5,000
6- Development: $25,000
7- Compliance: $8,000
8Total: $72,000/month
9
10Annual: $864,000
11Annual net P&L: $2.35M - $0.864M = $1.49M
12After 6+ years building HFT systems:
HFT requires substantial investment in infrastructure, but can be highly profitable with proper execution.
Technical Writer
NordVarg Team is a software engineer at NordVarg specializing in high-performance financial systems and type-safe programming.
Get weekly insights on building high-performance financial systems, latest industry trends, and expert tips delivered straight to your inbox.