问题描述
解决方案
在PTrade量化交易平台中,处理Tick级别的逐笔委托(Order)和逐笔成交(Transaction)数据主要有两种方式:
- 通过
tick_data回调函数被动接收:这是处理高频策略最常用的方式,系统每隔3秒(或更短,取决于频率设置)推送一次数据。 - 通过主动查询接口获取:使用
get_individual_entrust和get_individual_transaction函数主动拉取数据。
注意:获取逐笔数据通常需要开通 Level-2 行情权限,否则对应字段可能返回 None 或空数据。
以下是具体的实现代码和解析。
策略代码示例
def initialize(context):
# 初始化策略
# 设置我们要操作的股票池,这里以恒生电子为例
g.security = '600570.SS'
set_universe(g.security)
# 开启Tick级别数据接收(通常在实盘或Tick回测模式下自动生效)
# 注意:确保账户有Level-2权限
# 设置日志打印频率,避免日志过多
g.log_counter = 0
def tick_data(context, data):
"""
Tick数据回调函数,每隔一定时间(如3秒)触发一次
data结构:
{
'股票代码': {
'order': DataFrame/None (最近一条逐笔委托),
'tick': DataFrame (当前快照),
'transcation': DataFrame/None (最近一条逐笔成交, 注意API文档中key可能拼写为transcation)
}
}
"""
security = g.security
# 1. 获取该股票的数据包
if security not in data:
return
stock_data = data[security]
# ------------------------------------------------------
# 解析逐笔委托 (Order)
# ------------------------------------------------------
# 注意:如果没有L2权限或该时刻无委托,可能为None
order_df = stock_data.get('order')
if order_df is not None and len(order_df) > 0:
# 由于是DataFrame,通常取第一行(最近的一笔)
latest_order = order_df.iloc[0]
# 提取字段
order_time = latest_order['business_time'] # 时间戳
order_price = latest_order['hq_px'] # 委托价格
order_vol = latest_order['business_amount'] # 委托数量
order_dir = latest_order['business_direction'] # 委托方向 (0-卖, 1-买, 2-借入, 3-出借)
order_kind = latest_order['trans_kind'] # 委托类别 (1-市价, 2-限价, 3-本方最优)
# 简单的逻辑示例:打印大额买单
if order_dir == 1 and order_vol > 10000: # 假设大于100手算大单
log.info("[逐笔委托] 监测到大额买单: 时间=%s, 价格=%.2f, 数量=%d" % (order_time, order_price, order_vol))
# ------------------------------------------------------
# 解析逐笔成交 (Transaction)
# ------------------------------------------------------
# 注意:API文档中该Key有时拼写为 'transcation',需根据实际返回字典键值获取
trans_df = stock_data.get('transcation')
if trans_df is not None and len(trans_df) > 0:
latest_trans = trans_df.iloc[0]
# 提取字段
trans_time = latest_trans['business_time'] # 时间戳
trans_price = latest_trans['hq_px'] # 成交价格
trans_vol = latest_trans['business_amount'] # 成交数量
trans_dir = latest_trans['business_direction'] # 成交方向 (0-卖, 1-买)
trans_idx = latest_trans['trade_index'] # 成交编号
# 简单的逻辑示例:打印主动买入成交
if trans_dir == 1:
# 限制日志打印频率
g.log_counter += 1
if g.log_counter % 10 == 0:
log.info("[逐笔成交] 主动买入: 时间=%s, 价格=%.2f, 数量=%d" % (trans_time, trans_price, trans_vol))
def handle_data(context, data):
# 分钟/日线级别的逻辑(如果需要)
# 也可以在这里使用主动查询接口获取当日累积的逐笔数据
# 示例:主动查询逐笔成交(获取最近50条)
# 注意:is_dict=True 可以提高返回速度,返回字典格式
if is_trade(): # 仅在交易模式下有效
transactions = get_individual_transaction(stocks=[g.security], data_count=10, is_dict=True)
if transactions:
# 处理主动查询到的数据
pass
关键点解析
1. tick_data 中的数据结构
在 tick_data(context, data) 函数中,data 参数是一个字典。对于每一只股票,它包含三个主要键值:
tick: 当前的行情快照(盘口、最新价等)。order: 最近一条逐笔委托数据。transcation: 最近一条逐笔成交数据(请注意: PTrade文档及实际返回中,这个Key通常拼写为transcation而非 transaction,编写代码时需特别留意,或者先打印data[security].keys()确认)。
2. 字段含义
- 逐笔委托 (
order) 常用字段:hq_px: 委托价格。business_amount: 委托数量。business_direction: 0-卖, 1-买。trans_kind: 1-市价, 2-限价, 3-本方最优。
- 逐笔成交 (
transcation) 常用字段:hq_px: 成交价格。business_amount: 成交数量。business_direction: 0-卖(内盘/主动卖), 1-买(外盘/主动买)。buy_no/sell_no: 买方/卖方委托单号(可用于追踪大单拆单)。
3. 主动查询接口
除了在 tick_data 中被动接收,你也可以在 handle_data 或其他地方主动调用:
get_individual_entrust(stocks=..., is_dict=True): 获取逐笔委托。get_individual_transaction(stocks=..., is_dict=True): 获取逐笔成交。- 建议设置
is_dict=True,这样返回的是字典格式,解析速度比 DataFrame 快,更适合高频场景。
Q&A
Q1: 为什么我在回测中 tick_data 里取不到 order 和 transcation 数据?
A: 这通常有两个原因:
- 你选择的回测频率不是 "Tick级别"。只有在Tick级别回测或实盘交易中,
tick_data函数才会被调用。 - 你的账号或回测环境没有开通 Level-2 行情权限。逐笔数据属于 L2 高级行情,普通行情只包含快照(Snapshot)。
Q2: tick_data 推送的数据是全量的吗?
A: 不一定。tick_data 的触发频率通常是每3秒一次(或根据券商配置)。在 data 参数中返回的 order 和 transcation 通常是最近一条或该切片时间内的数据。如果市场交易非常活跃,3秒内发生了成百上千笔交易,单纯依靠 tick_data 的推送可能会漏掉中间的明细。如果需要极其精确的全量逐笔分析,建议结合 get_individual_transaction 主动查询,或者确认券商端的推送机制是否支持全量推送。
Q3: 如何判断逐笔成交是主动买入还是主动卖出?
A: 查看 transcation 数据中的 business_direction 字段。
1: 代表买(Buy),即外盘,通常理解为主动买入(买方以卖一价或更高价格成交)。0: 代表卖(Sell),即内盘,通常理解为主动卖出(卖方以买一价或更低价格成交)。