
加密货币量化策略的做市策略:如何根据订单簿不平衡度动态调整买卖报价?
了解量化交易者如何利用 Python 和订单簿失衡(OBI)动态调整加密货币做市报价、管理波动率与库存,并降低逆向选择风险。
对于量化交易者而言,做市是一项需要根据市场环境不断调整的定价工作。报价过宽,可能错失有利的成交机会;报价过于激进,则可能面临逆向选择风险,即订单刚刚成交,市场价格就朝着不利于自身持仓的方向移动。
在加密货币市场中,交易全天候进行,订单簿流动性也可能快速变化。订单簿失衡(Order Book Imbalance,OBI) 可以衡量买卖双方可见流动性的分布情况,并为系统化调整报价提供依据。
本文将介绍如何计算 OBI、如何将其转化为动态报价,以及如何使用 Python 处理实时加密货币订单簿数据。
为什么订单簿失衡对加密货币做市很重要
传统做市策略通常围绕参考价格设置买入报价和卖出报价。然而,即使中间价相同,买卖双方的挂单流动性不同,也可能意味着截然不同的交易环境。
例如,买单一侧的挂单量相对较大,可能表明市场上存在更多可见的买入意愿。相反,如果卖单一侧的挂单量更大,则可能意味着卖方流动性更充足。
OBI 通过衡量选定订单簿档位中买卖双方的成交量分布差异,量化这种失衡状态。它无法确定性地预测价格走势,但可以为量化交易者调整报价提供额外的参考信号。
如何计算订单簿失衡
一种常见的多档位 OBI 计算公式如下:
OBI = (V_bid - V_ask) / (V_bid + V_ask)其中:
- (V_{bid}) 表示所选档位内所有买单的总挂单量。
- (V_{ask}) 表示相同档位范围内所有卖单的总挂单量。
当买卖双方的总挂单量大于零时,OBI 的取值范围为 -1 到 +1。
| OBI 数值 | 含义 | 潜在的报价调整方式 |
|---|---|---|
| 大于零 | 买单侧可见挂单量更大 | 将报价中心向上调整 |
| 小于零 | 卖单侧可见挂单量更大 | 将报价中心向下调整 |
| 接近零 | 买卖双方挂单量相对均衡 | 让报价中心保持在接近中间价的位置 |
例如,如果选定的买单档位包含 800 个单位的挂单量,而卖单档位包含 400 个单位,则 OBI 约为 0.33。
这说明可见流动性存在不平衡,但并不意味着买方的实际交易压力已经得到确认。限价订单可能随时被撤销或补充,因此,OBI 应被视为多个信号之一,而不是独立使用的交易规则。
如何利用 OBI 实现动态报价
静态做市模型通常围绕市场中间价设置报价:
Mid = (BestBid + BestAsk) / 2其中,BestBid 是当前最高买价,BestAsk 是当前最低卖价。
为了将 OBI 纳入定价过程,可以对报价中心进行调整:
Center = Mid + κ × OBI随后,根据报价中心计算买入和卖出报价:
Bid = Center - hAsk = Center + h其中,\(h\) 表示目标半价差,\(\kappa\) 则用于控制 OBI 对报价中心的影响程度。由于 OBI 本身是无量纲数值,因此,\(\kappa\) 必须使用价格单位表示。
当 OBI 为正时,买入和卖出报价都会向上移动;当 OBI 为负时,两侧报价都会向下移动。这种方式能够调整报价所依据的参考价格,而不一定改变买卖价差本身。
在实际运行的做市策略中,半价差和调整系数还应考虑交易成本、库存风险、市场波动率、最小价格变动单位(Tick Size)以及执行风险。相关参数需要通过测试进行校准,不能假设它们在所有市场环境下都有效。
使用 Python 处理实时订单簿数据
要计算多档位 OBI,策略需要获取买卖双方的挂单价格和挂单量,而不仅仅是最新成交价。
AllTick 提供用于获取实时订单簿更新的 WebSocket 接口。其深度订阅文档介绍了订阅协议,以及下方代码使用的 bids 和 asks 字段。
以下示例订阅 BTCUSDT 的五档订单簿数据,计算 OBI,并输出用于演示的报价调整结果。该示例不会提交真实交易订单。
import json
import os
import time
import uuid
import threading
from urllib.parse import quote
import websocket
API_KEY = os.environ.get("ALLTICK_API_KEY")
if not API_KEY:
raise RuntimeError("Set the ALLTICK_API_KEY environment variable")
WS_URL = (
"wss://quote.alltick.co/quote-b-ws-api?token="
+ quote(API_KEY, safe="")
)
QUOTE_SHIFT_FACTOR = 0.25
def send_heartbeat(ws):
while ws.sock and ws.sock.connected:
time.sleep(10)
if not ws.sock or not ws.sock.connected:
break
try:
ws.send(json.dumps({
"cmd_id": 22000,
"seq_id": int(time.time()),
"trace": str(uuid.uuid4()),
"data": {}
}))
except Exception:
break
def on_open(ws):
ws.send(json.dumps({
"cmd_id": 22002,
"seq_id": int(time.time()),
"trace": str(uuid.uuid4()),
"data": {
"symbol_list": [
{"code": "BTCUSDT", "depth_level": 5}
]
}
}))
threading.Thread(
target=send_heartbeat, args=(ws,), daemon=True
).start()
def on_message(ws, message):
try:
packet = json.loads(message)
except json.JSONDecodeError:
return
if packet.get("cmd_id") != 22999:
return
book = packet.get("data") or {}
bids = book.get("bids") or []
asks = book.get("asks") or []
if not bids or not asks:
return
try:
bid_vol = sum(float(x.get("volume") or 0) for x in bids)
ask_vol = sum(float(x.get("volume") or 0) for x in asks)
best_bid = float(bids[0]["price"])
best_ask = float(asks[0]["price"])
except (TypeError, ValueError, KeyError):
return
total_vol = bid_vol + ask_vol
if total_vol <= 0 or best_ask <= best_bid:
return
obi = (bid_vol - ask_vol) / total_vol
mid = (best_bid + best_ask) / 2
spread = best_ask - best_bid
shift = QUOTE_SHIFT_FACTOR * spread * obi
model_bid = mid - spread / 2 + shift
model_ask = mid + spread / 2 + shift
print(
f"{book.get('code')} OBI={obi:.3f} "
f"bid={model_bid:.2f} ask={model_ask:.2f}"
)
def start():
while True:
ws = websocket.WebSocketApp(
WS_URL,
on_open=on_open,
on_message=on_message,
on_error=lambda ws, err: print(f"WebSocket error: {err}"),
)
ws.run_forever()
time.sleep(3)
if __name__ == "__main__":
start()这段代码利用当前最优买卖价之间的价差来演示报价中心的移动。其中,报价调整系数仅用于示例,并非经过验证的交易参数。
生产环境中的系统还需要进一步处理订单提交、重连状态、数据过期、价格精度、库存限制以及特定交易场所的执行规则。
如何结合波动率和库存管理控制逆向选择风险
单独使用 OBI 可能产生大量噪声信号。较大的挂单可能在成交前消失,而突发的市场波动也可能使原本合理的报价迅速失效。
更稳健的加密货币做市策略可以结合以下三种控制机制:
- 波动率过滤: 当短期波动率上升时,扩大报价价差,或降低报价对 OBI 的敏感程度。
- 库存管理: 当累积持仓形成过大的方向性风险时,调整报价中心,以控制持仓敞口。
- 信号持续性判断: 检查订单簿失衡是否在多个连续更新中持续存在,而不是对每次快照变化都立即作出反应。
这三种机制分别应对不同的风险。波动率过滤用于响应市场环境变化,库存管理用于限制持仓集中度,而信号持续性判断则有助于降低策略对短暂订单簿变化的敏感度。
部署前如何测试策略
OBI 为正,并不意味着提高报价就一定能够改善盈利能力。量化交易者需要验证这一信号是否有助于预测后续价格变化,以及是否能够改善实际成交结果。
建议记录以下数据:
- 订单簿时间戳。
- 选定档位的买卖价格与挂单量。
- 计算得到的 OBI 数值。
- 策略生成的买入和卖出报价。
- 后续中间价的变化情况。
评估时,应重点关注订单成交率、成交后的不利价格变动、交易成本、库存敞口,以及策略在不同波动率环境下的净表现。
还需要注意一个重要的数据限制:根据 AllTick 的文档说明,其 WebSocket 深度订阅接口提供实时订单簿更新,而非历史订单簿数据。如果量化交易者需要开展可重复的历史 OBI 回测,就需要自行归档深度数据流,并保留时间戳及数据质量检查记录。
如需接入实时数据,可以查看 AllTick 加密货币 API,并确认当前账户是否支持所需的交易品种和订单簿深度。
实用的做市策略不会将订单簿失衡视为确定性的价格预测工具,而是利用 OBI 调整报价中心,同时结合波动率和库存风险控制,并通过实际成交数据验证这种调整是否真正创造了价值。