问题描述
解决方案
在PTrade中,判断委托状态的核心在于获取 Order对象,并检查其 status 属性。
核心步骤
- 获取订单对象:使用
get_order(order_id)或get_orders()获取订单信息。 - 检查
status字段:根据数据字典中的定义判断状态。- '8':已成(全部成交)
- '7':部成(部分成交,剩余部分仍在挂单中)
- '9':废单(无效委托,通常因资金不足、价格超限或非交易时间导致)
- '6':已撤(订单已取消)
- '5':部撤(部分成交后,剩余部分已取消)
策略代码示例
以下是一个完整的策略示例。该策略在 initialize 中设置股票,在 handle_data 中下单,并在随后的运行中持续监控该订单的状态,根据不同状态打印日志或执行逻辑。
def initialize(context):
# 设置要操作的股票,这里以恒生电子为例
g.security = '600570.SS'
set_universe(g.security)
# 用于存储订单ID的全局变量
g.order_id = None
# 标记是否已经下过单
g.has_ordered = False
def handle_data(context, data):
# 1. 如果还没有下单,先执行下单操作
if not g.has_ordered:
# 下单买入100股,这里故意使用限价单以便观察状态(如果是市价单可能瞬间成交)
# 注意:为了演示废单,你可以将价格设置得非常低(如1.0),或者数量设置超过资金上限
current_price = data[g.security]['close']
g.order_id = order(g.security, 100, limit_price=current_price)
if g.order_id is not None:
log.info("已下单,订单ID: %s" % g.order_id)
g.has_ordered = True
else:
log.error("下单失败,未生成订单ID")
return
# 2. 如果已经下单,获取订单对象并检查状态
if g.order_id:
# get_order 返回的是一个列表,包含一个Order对象
order_list = get_order(g.order_id)
if order_list is not None and len(order_list) > 0:
# 获取具体的订单对象
my_order = order_list[0]
status = my_order.status
# --- 状态判断逻辑 ---
# 情况一:全部成交
if status == '8':
log.info("【全部成交】订单 %s 已全部成交,成交数量: %s" % (g.order_id, my_order.filled))
# 后续操作:例如更新策略状态,准备卖出等
# g.order_id = None # 重置ID以便下一次逻辑使用
# 情况二:部分成交
elif status == '7':
log.info("【部分成交】订单 %s 部分成交,已成交: %s,剩余: %s" % (
g.order_id, my_order.filled, my_order.amount - my_order.filled
))
# 后续操作:可以选择继续等待,或者如果长时间未完全成交则撤单
# cancel_order(g.order_id)
# 情况三:废单
elif status == '9':
log.error("【废单】订单 %s 是废单,请检查资金或价格限制。" % g.order_id)
# 后续操作:重置状态,尝试重新下单或停止策略
g.has_ordered = False
g.order_id = None
# 情况四:已撤单 (包含 '6':已撤 和 '5':部撤)
elif status in ['6', '5']:
log.info("【已撤单】订单 %s 已撤销。" % g.order_id)
# 情况五:已报/待报 (订单还在排队中)
elif status in ['1', '2', '3', '4']:
log.info("【挂单中】订单 %s 正在排队,状态码: %s" % (g.order_id, status))
else:
log.info("订单 %s 当前状态码: %s" % (g.order_id, status))
关键点说明
get_order返回值:请注意get_order(order_id)返回的是一个 list,所以代码中使用了order_list[0]来获取实际的 Order 对象。- 实盘与回测的区别:
- 回测:状态更新是基于撮合逻辑的,通常在下一个
handle_data周期或者同一周期的后续逻辑中可以看到状态变化。 - 交易(实盘):状态更新依赖柜台回报。如果您需要极低延迟的状态监控(例如高频交易),建议使用
on_order_response回调函数,它会在委托状态发生变化时立即被触发,比在handle_data中轮询更高效。
- 回测:状态更新是基于撮合逻辑的,通常在下一个
补充:使用 on_order_response (仅限交易模式)
如果您是在实盘交易中,推荐使用回调函数来处理状态变化:
def on_order_response(context, order_list):
# order_list 是发生变化的委托单列表
for order_dict in order_list:
status = order_dict['status']
order_id = order_dict['order_id']
if status == '8':
log.info("实盘主推:订单 %s 全部成交" % order_id)
elif status == '9':
log.error("实盘主推:订单 %s 废单,原因: %s" % (order_id, order_dict.get('error_info', '未知')))
Q&A
Q: 为什么我的订单状态一直是 "2" (已报)?
A: "2" 表示订单已经成功报送到交易所,正在排队等待成交。如果价格没有达到市场价,或者流动性不足,订单会一直保持这个状态直到成交或收盘自动撤单。
Q: 废单(状态9)常见的原因有哪些?
A: 常见原因包括:可用资金不足、可用持仓不足(卖出时)、价格超过涨跌停限制、不在交易时间段内、委托数量不符合最小单位(如不足100股)。
Q: 部分成交(状态7)后,剩余部分会自动撤销吗?
A: 不会。剩余部分会继续挂在市场上等待成交。如果您希望在部分成交后不再等待,需要手动调用 cancel_order() 函数撤销剩余部分。撤销成功后,状态会变为 '5' (部撤)。