Market Making and Liquidity Provision › Implementing a Market Making Simulation
Quantitative FinanceAll chapters Market Making and Liquidity Provision › Implementing a Market Making SimulationOne section · Sections in this chapter7 / 13 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
Let's build a complete simulation to see how these concepts work together in practice. We'll simulate your strategy using the Avellaneda-Stoikov model over a trading day. This simulation will illustrate how the theoretical framework translates into actual trading behavior and outcomes.
import numpy as np
import pandas as pd
class MarketMakingSimulator:
"""
Simulates a market making strategy using Avellaneda-Stoikov quotes.
"""
def __init__(
self,
initial_price=100,
volatility=0.3,
gamma=0.1,
k=1.5,
lambda_base=5.0,
dt=1 / (252 * 6.5 * 60),
):
"""
Parameters:
-----------
initial_price : float - Starting mid price
volatility : float - Annualized volatility
gamma : float - Risk aversion
k : float - Order book parameter
lambda_base : float - Base arrival rate (orders per minute)
dt : float - Time step (fraction of year)
"""
self.S0 = initial_price
self.sigma = volatility
self.gamma = gamma
self.k = k
self.lambda_base = lambda_base
self.dt = dt
def simulate(self, n_steps, T_total):
"""
Run simulation for n_steps.
Parameters:
-----------
n_steps : int - Number of time steps
T_total : float - Total time horizon in years
Returns:
--------
dict with simulation results
"""
np.random.seed(789)
# Initialize tracking arrays
prices = np.zeros(n_steps + 1)
inventories = np.zeros(n_steps + 1)
cash = np.zeros(n_steps + 1)
bids = np.zeros(n_steps)
asks = np.zeros(n_steps)
trades = []
prices[0] = self.S0
for t in range(n_steps):
S = prices[t]
q = inventories[t]
T_remaining = T_total - t * self.dt
# Calculate optimal quotes
bid, ask, _, _ = avellaneda_stoikov_quotes(
S, q, self.gamma, self.sigma, max(T_remaining, 1e-6), self.k
)
bids[t] = bid
asks[t] = ask
# Calculate fill probabilities
delta_bid = S - bid
delta_ask = ask - S
# Poisson arrival probabilities for this time step
lambda_bid = (
self.lambda_base
* np.exp(-self.k * delta_bid)
* self.dt
* 252
* 6.5
* 60
)
lambda_ask = (
self.lambda_base
* np.exp(-self.k * delta_ask)
* self.dt
* 252
* 6.5
* 60
)
# Simulate arrivals (simplify to at most one order per time step)
bid_fill = np.random.random() < lambda_bid
ask_fill = np.random.random() < lambda_ask
# Update inventory and cash
inventories[t + 1] = inventories[t]
cash[t + 1] = cash[t]
if bid_fill: # Market maker buys
inventories[t + 1] += 1
cash[t + 1] -= bid
trades.append(
{"time": t, "side": "buy", "price": bid, "qty": 1}
)
if ask_fill: # Market maker sells
inventories[t + 1] -= 1
cash[t + 1] += ask
trades.append(
{"time": t, "side": "sell", "price": ask, "qty": 1}
)
# Simulate price movement (arithmetic Brownian motion)
prices[t + 1] = (
prices[t] + self.sigma * np.sqrt(self.dt) * np.random.randn()
)
# Calculate final P&L
final_value = cash[-1] + inventories[-1] * prices[-1]
initial_value = 0
return {
"prices": prices,
"inventories": inventories,
"cash": cash,
"bids": bids,
"asks": asks,
"trades": pd.DataFrame(trades),
"final_pnl": final_value - initial_value,
"final_inventory": inventories[-1],
}# Run simulation for a full trading day (6.5 hours, ~23,400 seconds)
# Using minute-level granularity
n_minutes = 390 # 6.5 hours
T_day = 1 / 252 # One trading day
simulator = MarketMakingSimulator(
initial_price=100,
volatility=0.3,
gamma=0.1,
k=1.5,
lambda_base=2.0, # Average 2 orders per minute at fair price
)
results = simulator.simulate(n_minutes, T_day)Market Making Simulation Results - Full Trading Day ============================================================ Trading Activity: Total trades: 591 Buys: 290 Sells: 301 Position: Final inventory: -11 shares Max long: 4 shares Max short: -15 shares P&L: Final P&L: $381.37 Final inventory value: $-1100.14 Cash position: $1481.51


The simulation illustrates how the market making strategy works in practice. The top panel shows the mid price evolution with your bid and ask quotes, while trade executions are marked with triangles. The bottom panel shows how inventory evolves over time. Notice how it tends to fluctuate around zero because the quotes encourage mean reversion. When inventory drifts positive, the lower quotes attract sellers to buy from you, pulling inventory back down. When inventory drifts negative, the higher quotes attract buyers to sell to you.