MarketMakerHFT001: Crypto Case Study for High-Frequency Market Making
这是 MarketMakerHFT001。
这篇不是公开任何原始数据,也不是发布私有学习材料。
这篇做的是一件更重要的事:
1
把一次 crypto 高频做市学习,抽象成 public-safe 的高频交易 / 做市商研究框架。
核心边界先说清楚:
1
2
3
4
1. 这是学习笔记,不是实盘做市系统。
2. 这是以 crypto market 为案例,不是宣称我已经精通 crypto 做市。
3. 高频做市理论可以迁移到股票、期货、ETF、期权、外汇、数字货币等市场。
4. 公开版只保留通用方法、工程结构、代码片段和研究问题,不暴露原始数据、路径、私有来源名称或私有材料标识。
更准确的项目定位是:
1
Crypto tick-level market making research and learning prototype.
英文面试表达:
1
2
3
4
I studied a crypto HFT market making workflow as a learning prototype.
The project covers tick data normalization, order book features, short-horizon price modeling,
AS/ASQ-style quoting, inventory-aware market making, fee/rebate-aware backtesting,
and the key gap between research backtests and production-grade HFT systems.
中文表达:
1
2
我系统学习了一套以 crypto tick 数据为案例的高频做市研究流程,覆盖 tick 数据标准化、盘口特征工程、短期价格模型、
AS/ASQ 做市报价、库存约束、手续费/返佣回测,以及研究原型与生产级高频系统之间的差距。
1. 做市商到底在做什么
普通交易者常常想的是:
1
2
3
买低卖高
预测方向
抓趋势
做市商想的是:
1
2
3
同时挂 bid 和 ask
用 spread / rebate / order flow edge 获利
持续控制库存和逆向选择风险
一个最简盘口:
1
2
3
4
5
best bid: 2999.9, size 10
best ask: 3000.1, size 12
mid price = (2999.9 + 3000.1) / 2 = 3000.0
spread = 3000.1 - 2999.9 = 0.2
做市商可能同时挂:
1
2
bid quote = 2999.9
ask quote = 3000.1
如果两边都能成交,并且价格没有明显单边冲击,就可能赚到 spread。
但现实更难:
1
2
3
4
5
1. 买入后价格继续跌,库存亏损。
2. 卖出后价格继续涨,库存亏损。
3. 你的订单不一定排在队列前面。
4. 你的报价可能被 informed trader 打掉。
5. 高频环境里 latency、撤单、限速、交易所撮合规则都影响结果。
所以做市的核心不是“挂两个单就赚钱”,而是:
1
quote placement + inventory control + adverse selection control + execution realism.
2. 为什么用 Crypto 作为第一仗
Crypto 市场适合作为高频做市学习案例,原因不是它更简单,而是它的数据和市场结构很适合练习:
1
2
3
4
5
6
1. 7x24 连续交易。
2. tick 数据丰富。
3. 盘口和成交行为频繁。
4. maker / taker fee structure 清晰。
5. 永续合约有 funding、杠杆、保证金、强平等独特机制。
6. 很多交易所 API 和数据格式相对容易接触。
但 crypto 也有自己的复杂性:
1
2
3
4
5
1. 极端波动更强。
2. 交易所稳定性差异大。
3. fee / rebate / funding 对收益影响很大。
4. 真实撮合、撤单限制、风控、断线恢复非常重要。
5. 市场参与者结构和传统股票/期货不同。
所以这篇的正确理解是:
1
Crypto is a case study for learning market making, not the full universe of market making.
3. 高频做市系统的最小架构
一个研究型高频做市系统可以拆成九层:
1
2
3
4
5
6
7
8
9
Raw Market Data
-> Data Parser
-> Standard Tick Object
-> Local Data Catalog
-> Feature Engineering
-> Short-Horizon Price Model
-> Quoting Model
-> Backtest / Simulation
-> Diagnostics
更工程化一点:
1
2
3
4
5
6
7
8
9
1. Data Ingestion
2. Data Normalization
3. Instrument Metadata
4. Order Book State
5. Microstructure Features
6. Quote Engine
7. Inventory Engine
8. Execution Simulator
9. Risk / Metrics / Report
这和中低频量化最大区别是:
1
2
中低频策略更关注 bar data、signal、position、portfolio。
高频做市更关注 tick、order book、queue、fill、latency、inventory、fees。
4. 数据层:从 Raw Tick 到 Standard Tick
高频做市的第一步不是模型,而是数据标准化。
一个 raw bookTicker 类数据通常包含:
1
2
3
4
5
event_time
best_bid_price
best_bid_qty
best_ask_price
best_ask_qty
我们可以抽象成统一对象:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from dataclasses import dataclass
@dataclass
class QuoteTick:
ts_event: int
bid_price: float
ask_price: float
bid_size: float
ask_size: float
@property
def mid_price(self) -> float:
return (self.bid_price + self.ask_price) / 2
@property
def spread(self) -> float:
return self.ask_price - self.bid_price
数据 parser 的核心任务:
1
2
3
4
5
6
7
8
def parse_book_ticker(row) -> QuoteTick:
return QuoteTick(
ts_event=int(row["event_time"]),
bid_price=float(row["best_bid_price"]),
ask_price=float(row["best_ask_price"]),
bid_size=float(row["best_bid_qty"]),
ask_size=float(row["best_ask_qty"]),
)
真实工程里还要处理:
1
2
3
4
5
6
7
8
1. price precision
2. quantity precision
3. timestamp timezone
4. duplicate ticks
5. missing values
6. out-of-order events
7. exchange-specific schema
8. instrument metadata
这一步非常关键。因为高频系统里,错误数据会直接污染回测结论。
5. Local Catalog:为什么要存成标准格式
直接用 CSV 也能研究,但不够工程化。
更稳的做法是:
1
2
3
4
raw csv/json
-> normalized tick objects
-> columnar local catalog
-> reusable backtest data source
常见选择:
1
2
3
4
5
6
Parquet
Arrow
HDF5
DuckDB
ClickHouse
specialized backtest catalog
为什么偏好 columnar / catalog:
1
2
3
4
5
1. tick 数据量大。
2. 查询特定时间范围更快。
3. schema 更稳定。
4. 便于复现实验。
5. 便于按 instrument / date / data type 管理。
一个简化 catalog 思路:
1
2
3
4
def write_ticks_to_catalog(ticks, root, symbol, date):
path = f"{root}/{symbol}/quote_ticks/{date}.parquet"
frame = ticks_to_dataframe(ticks)
frame.to_parquet(path, index=False)
这个步骤背后的思想是:
1
2
不要把一次性 notebook 变成最终系统。
要把数据变成可复用、可追踪、可复验的研究资产。
6. 价格模型:Mid Price 不够
最基础价格:
1
mid_price = (best_bid + best_ask) / 2
但 mid price 默认假设 bid/ask 两边对称,这在真实盘口里经常不成立。
例如:
1
2
best bid size = 100
best ask size = 10
这表示买盘更厚,短期价格可能更容易向上。
于是可以构造 order book imbalance:
1
2
3
4
5
def order_book_imbalance(bid_size, ask_size):
denom = bid_size + ask_size
if denom == 0:
return 0.0
return (bid_size - ask_size) / denom
再构造 adjusted mid price:
1
2
3
4
5
def adjusted_mid_price(bid, ask, bid_size, ask_size):
mid = (bid + ask) / 2
spread = ask - bid
imbalance = order_book_imbalance(bid_size, ask_size)
return mid + spread * imbalance / 2
直觉:
1
2
买盘更厚 -> adjusted_mid_price 高于 mid_price
卖盘更厚 -> adjusted_mid_price 低于 mid_price
这就是 microstructure price model 的起点。
7. 高频特征工程
高频特征大致分两类。
第一类:Order Book Features
1
2
3
4
5
6
7
8
9
10
mid price
spread
order book imbalance
volume imbalance
VWAP around top levels
book slope
advanced OBI
price/volume changes at best bid/ask
short-horizon volatility
momentum
第二类:Trade Features
1
2
3
4
5
6
7
8
taker buy volume
taker sell volume
gross buy ratio
net buy ratio
buy/sell concentration
trade volume rolling sum
average buy/sell trade price
trade interval distribution
一个简化特征函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def build_features(df):
df = df.copy()
df["mid_price"] = (df["best_bid_price"] + df["best_ask_price"]) / 2
df["spread"] = df["best_ask_price"] - df["best_bid_price"]
df["obi"] = (
(df["best_bid_qty"] - df["best_ask_qty"]) /
(df["best_bid_qty"] + df["best_ask_qty"])
)
df["adj_mid"] = df["mid_price"] + df["spread"] * df["obi"] / 2
df["ret_1s"] = df["mid_price"].shift(-1) / df["mid_price"] - 1
df["vol_10s"] = df["ret_1s"].rolling(10).std()
return df
真正的高频特征要更小心:
1
2
3
4
5
1. 不能用未来信息。
2. trade 和 book tick 对齐要严格。
3. 不同交易所时间戳含义不同。
4. rolling window 不能跨越不可见未来。
5. 特征必须能在决策时刻实时获得。
8. AS / ASQ 做市模型
高频做市里一个经典框架是 Avellaneda-Stoikov market making。
它想解决的问题是:
1
2
给定当前价格、波动率、市场单到达速度、风险厌恶和库存,
应该把 bid / ask 挂在哪里?
一个简化表达:
1
2
bid_quote = reference_price - bid_spread
ask_quote = reference_price + ask_spread
这里的 reference_price 可以是:
1
2
3
4
mid price
micro price
adjusted mid price
model-predicted mid price
关键参数:
1
2
3
4
5
6
sigma: short-term volatility
A: market order arrival intensity scale
k: market order arrival decay with quote distance
gamma: risk aversion
q: current inventory
Q: inventory limit
简化代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import math
def bid_spread(sigma, A, k, gamma, q):
base = (1 / gamma) * math.log(1 + gamma / k)
inventory_term = (2 * q + 1) / 2 * math.sqrt(
sigma ** 2 * gamma / (2 * k * A) * (1 + gamma / k) ** (1 + k / gamma)
)
return base + inventory_term
def ask_spread(sigma, A, k, gamma, q):
base = (1 / gamma) * math.log(1 + gamma / k)
inventory_term = (2 * q - 1) / 2 * math.sqrt(
sigma ** 2 * gamma / (2 * k * A) * (1 + gamma / k) ** (1 + k / gamma)
)
return base - inventory_term
库存的直觉:
1
2
q > 0: 已经偏多,需要更积极卖出、更谨慎买入。
q < 0: 已经偏空,需要更积极买入、更谨慎卖出。
这就是 inventory-aware quoting。
9. Market Order Arrival:A 和 k 怎么估
AS/ASQ 里 A 和 k 描述的是:
1
报价离 mid 越远,被 market order 打到的概率越低。
常见形式:
1
lambda(delta) = A * exp(-k * delta)
其中:
1
2
delta = quote distance from reference price
lambda = order arrival intensity
一个研究型估计方法:
1
2
3
4
5
6
7
8
9
10
import numpy as np
from scipy.optimize import curve_fit
def exp_decay(x, A, k):
return A * np.exp(-k * x)
def fit_arrival_intensity(distances, arrival_rates):
params, _ = curve_fit(exp_decay, distances, arrival_rates)
A, k = params
return A, k
实际估计时需要:
1
2
3
4
1. 按 tick size 划分 quote distance。
2. 统计不同距离上的 hit frequency。
3. 用历史窗口估计 arrival intensity。
4. 注意 regime shift 和交易时间差异。
这一步把理论模型接到了真实盘口数据。
10. ML Price Model + Market Making
传统 AS/ASQ 用当前 mid price 做报价中心。
增强版本可以用短期价格预测:
1
features -> predicted short-horizon return -> predicted reference price
例如:
1
2
def reference_price_with_prediction(mid_price, predicted_return):
return mid_price * (1 + predicted_return)
然后做市报价:
1
2
3
ref = reference_price_with_prediction(mid_price, pred_ret)
bid = ref - bid_spread(sigma, A, k, gamma, q)
ask = ref + ask_spread(sigma, A, k, gamma, q)
这条线的核心思想:
1
2
如果短期预测向上,可以整体上移 bid/ask quote。
如果短期预测向下,可以整体下移 bid/ask quote。
但这里风险很大:
1
2
3
4
1. 短期预测很容易过拟合。
2. correlation 不等于可交易收益。
3. 一点点 latency 就可能毁掉信号。
4. 预测越激进,越容易变成方向交易而不是做市。
所以更稳的表达是:
1
ML is used as a reference-price adjustment layer, not as a guarantee of alpha.
11. 回测逻辑:从 Quote 到 PnL
一个简化做市回测:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def simulate_market_maker(rows, params):
q = 0 # inventory
cash = 0.0
pnl = []
fees = 0.0
for i in range(len(rows) - 1):
row = rows.iloc[i]
nxt = rows.iloc[i + 1]
ref = row["reference_price"]
bid = ref - bid_spread(params.sigma, params.A, params.k, params.gamma, q)
ask = ref + ask_spread(params.sigma, params.A, params.k, params.gamma, q)
# keep quotes on maker side
bid = min(bid, row["best_bid_price"])
ask = max(ask, row["best_ask_price"])
buy_filled = q <= params.max_inventory and nxt["best_bid_price_min"] < bid
sell_filled = q >= -params.max_inventory and nxt["best_ask_price_max"] > ask
if buy_filled:
q += 1
cash -= bid
fees += bid * params.maker_rebate
if sell_filled:
q -= 1
cash += ask
fees += ask * params.maker_rebate
mark_to_market = cash + q * nxt["mid_price"]
pnl.append(mark_to_market + fees)
return pnl
这个回测框架里最值得拷打的点是:
1
fill assumption.
因为真实市场里:
1
2
3
4
价格触碰你的 quote,不代表你的订单一定成交。
你排在队列后面,前面可能有很多单。
你撤单可能来不及。
市场可能先打掉你,再反向移动。
所以研究型回测必须主动写出限制:
1
This simplified backtest does not fully model queue position, latency, partial fills, cancel/replace behavior, or exchange matching rules.
12. Maker Rebate 和 Fee 是核心变量
做市收益不只来自 spread。
很多市场里,费用结构是:
1
2
3
4
5
maker fee / rebate
taker fee
funding
borrow cost
exchange tier
Crypto 做市尤其要关注:
1
2
3
4
1. maker rebate 能否覆盖 adverse selection。
2. taker fee 会不会吞掉 hedge / unwind 成本。
3. funding 对永续合约持仓的影响。
4. 交易所等级和成交量门槛。
有些做市原型会出现:
1
交易本身亏钱,但加上 maker rebate 后赚钱。
这不是坏事,但必须谨慎:
1
2
3
4
1. rebate policy 会变。
2. 成交量刷出来不等于真实收益。
3. adverse selection 可能在极端行情里吞掉 rebate。
4. 真实延迟和排队位置会影响成交质量。
13. 高频做市和普通 RAG/Agent/Quant OS 的连接
这个项目对 Research OS 的启发很强。
因为高频做市天然要求:
1
2
3
4
5
6
1. 数据 lineage 清楚。
2. 回测假设清楚。
3. 参数估计清楚。
4. 每个信号是否可实时获得必须清楚。
5. 每个成交假设都必须被审计。
6. 每个实验必须能复现。
可以形成一个 Market Making Research OS:
1
2
3
4
5
6
7
8
Data Card
Feature Card
Model Card
Quote Policy Card
Execution Assumption Card
Risk Card
Backtest Report
Grilling Q&A
这也解释了为什么高频交易训练很适合磨炼工程思维:
1
2
3
4
它不允许模糊。
时间戳错一点,结论就错。
fill 假设错一点,收益就虚。
fee 忽略一点,策略就失真。
14. 跨市场迁移:为什么不止 Crypto
高频做市理论不是 crypto 专属。
可以迁移到:
1
2
3
4
5
6
7
Equities
Futures
Options
ETF
FX
Crypto spot
Crypto perpetual futures
通用问题是:
1
2
3
4
5
6
7
1. 当前 fair price 是多少?
2. bid / ask 应该挂多远?
3. 当前库存偏不偏?
4. 市场单到达概率如何?
5. 被 adverse selected 的概率多大?
6. fee / rebate / tick size 是否支持做市?
7. 回测成交假设是否接近真实?
不同市场的差别:
1
2
3
4
5
股票:交易时间、撮合规则、监管、借券、tick size、队列更严格。
期货:合约乘数、保证金、主力切换、夜盘、交割。
期权:希腊字母、波动率面、hedging、宽盘口。
FX:分散流动性、dealer market、last look。
Crypto:7x24、交易所差异、funding、链上/交易所账户风险。
所以我们可以把 crypto 当作第一仗,但最终目标是理解通用 market making。
15. 面试拷打问题
必须能答:
1
2
3
4
5
6
7
8
9
10
11
12
Q1: 做市和方向交易有什么区别?
Q2: 做市商为什么能赚钱?
Q3: spread、rebate、inventory、adverse selection 分别是什么?
Q4: 什么是 order book imbalance?为什么它可能预测短期价格?
Q5: mid price、micro price、adjusted mid price 有什么区别?
Q6: AS/ASQ 模型里的 sigma、A、k、gamma、q、Q 分别是什么?
Q7: market order arrival intensity 怎么估?
Q8: 为什么高频回测的 fill assumption 很危险?
Q9: queue position 为什么重要?
Q10: 如果你的回测没有 latency,会有什么问题?
Q11: maker rebate 策略为什么可能脆弱?
Q12: 你这个项目离生产级系统还差什么?
一个稳的回答框架:
1
2
3
4
5
This is a research prototype.
The goal is to understand the market making workflow: tick data normalization, microstructure feature engineering,
ASQ-style inventory-aware quoting, and fee-aware backtesting.
The biggest limitation is execution realism: queue position, latency, partial fills, cancel/replace logic,
and exchange-specific matching rules are not fully modeled yet.
16. 简历表达版本
一行版:
1
Studied a crypto HFT market making prototype covering tick data normalization, order-book features, ASQ-style quoting, inventory constraints, and fee-aware backtesting.
三行版:
1
2
3
Built a research prototype for crypto tick-level market making.
Normalized best bid/ask tick data, engineered microstructure features, estimated ASQ parameters, and tested inventory-aware bid/ask quote rules.
Analyzed key backtest limitations including queue position, latency, partial fills, maker rebate dependence, and adverse selection.
中文版:
1
学习并复现以数字货币 tick 数据为案例的高频做市研究原型,覆盖盘口数据标准化、微观结构特征、ASQ 做市报价、库存约束和手续费/返佣回测,并重点分析高频回测中的队列位置、延迟、成交假设和逆向选择风险。
17. 公开安全边界
这篇公开文章保留:
1
2
3
4
5
6
通用市场微观结构概念
通用高频做市架构
可复用伪代码
通用 AS/ASQ 参数解释
公开可讨论的工程风险
面试可讲的项目边界
这篇公开文章不包含:
1
2
3
4
5
6
7
8
原始数据
私有文件路径
私有来源名称
内部材料标识
未脱敏结果
具体可交易 alpha
生产级交易参数
真实账户或交易记录
这是正确的公开方式:
1
show capability, not leak edge.
18. 下一步
这个方向后续可以继续做三篇:
1
2
3
MarketMakerHFT002: Order Book Imbalance and Micro Price
MarketMakerHFT003: ASQ Model and Inventory-Aware Quoting
MarketMakerHFT004: Backtest Realism - Queue Position, Latency, Fill Assumption
更工程化的下一步:
1
2
3
4
5
1. 用公开样例数据构造一个极小 tick dataset。
2. 写一个 minimal market making simulator。
3. 加入 queue position / latency / fee 参数。
4. 输出 public-safe experiment report。
5. 把它接入 Pengyi Quant Research OS 的 experiment ledger。
这一仗的意义不是证明我们已经是高频做市专家,而是:
1
2
从中低频期货因子研究,推进到 tick-level market microstructure。
从策略信号,推进到报价、库存、成交、费用和真实交易系统约束。
这就是 MarketMakerHFT001 的位置。