3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
on_trade_response 管理持仓?在 ptrade 实盘交易环境中,柜台返回的持仓数据同步通常存在一定的时滞(一般在 6 秒左右)。如果策略属于高频、Tick 级交易或需要在极短时间内连续下单(例如双均线快速翻转、网格交易等),直接调用 get_position() 或 context.portfolio.positions 可能会因为数据未及时同步而导致重复下单或超卖/超买。
on_trade_response 是成交主推回调函数,当柜台有订单成交时,会第一时间向策略推送成交信息。通过在本地维护一个全局变量持仓字典 g.local_positions,并在 on_trade_response 中进行增量更新,可以实现毫秒级的持仓状态同步。
before_trading_start(每日盘前)获取当前账户的真实持仓,初始化本地缓存 g.local_positions。on_trade_response 中解析推送的 trade_list:
entrust_bs == '1'),本地持仓数量增加。entrust_bs == '2'),本地持仓数量减少,可用持仓数量相应减少。handle_data 或 tick_data 中,不再调用 get_position(),而是直接读取 g.local_positions 获取最新持仓。# -*- coding: utf-8 -*-
def initialize(context):
# 设置操作的股票池
g.security = '600570.SS'
set_universe(g.security)
# 初始化本地持仓缓存字典
# 格式:{ '股票代码': {'amount': 总持仓, 'enable_amount': 可用持仓} }
g.local_positions = {}
# 设置策略参数:接收非本策略产生的成交主推(可选,根据实际需求配置)
set_parameters(receive_other_response="1")
def before_trading_start(context, data):
log.info("--- 盘前初始化持仓缓存 ---")
g.local_positions.clear()
# 获取当前账户的所有真实持仓
all_positions = get_positions()
for code, pos in all_positions.items():
g.local_positions[code] = {
'amount': pos.amount,
'enable_amount': pos.enable_amount
}
log.info("初始本地持仓缓存: %s" % g.local_positions)
def on_trade_response(context, trade_list):
"""
成交主推回调函数:当有订单成交时,柜台会第一时间推送
"""
for trade in trade_list:
code = trade['stock_code']
entrust_bs = trade['entrust_bs'] # '1'-买,'2'-卖
filled_amount = int(trade['business_amount'])
status = trade['status']
# 仅处理已成('8')或部成('7')的推送
if status in ['7', '8']:
# 如果本地缓存中没有该股,先初始化
if code not in g.local_positions:
g.local_positions[code] = {'amount': 0, 'enable_amount': 0}
if entrust_bs == '1': # 买入成交
g.local_positions[code]['amount'] += filled_amount
# 注意:A股 T+1 机制下,当天买入的股票可用资金减少,但可用持仓不增加(次日才可用)
# 如果是可转债或T+0品种,可在此处同时增加 enable_amount
if code.startswith('11') or code.startswith('12'): # 简单判断可转债
g.local_positions[code]['enable_amount'] += filled_amount
log.info("【买入主推】%s 成交 %d 股,最新本地持仓: %s" % (code, filled_amount, g.local_positions[code]))
elif entrust_bs == '2': # 卖出成交
g.local_positions[code]['amount'] -= filled_amount
g.local_positions[code]['enable_amount'] -= filled_amount
# 规避减至负数边界情况
if g.local_positions[code]['amount'] < 0:
g.local_positions[code]['amount'] = 0
if g.local_positions[code]['enable_amount'] < 0:
g.local_positions[code]['enable_amount'] = 0
log.info("【卖出主推】%s 成交 %d 股,最新本地持仓: %s" % (code, filled_amount, g.local_positions[code]))
def handle_data(context, data):
# 示例:获取本地缓存持仓
code = g.security
pos_info = g.local_positions.get(code, {'amount': 0, 'enable_amount': 0})
current_amount = pos_info['amount']
enable_amount = pos_info['enable_amount']
# 策略逻辑中使用本地持仓判断,完美规避 6 秒延迟
if current_amount == 0:
# 执行买入逻辑
order(code, 100)
# 为了防止在主推未到达的极短间隙重复下单,可在下单后立即虚拟占扣本地可用仓位
# g.local_positions[code] = {'amount': 100, 'enable_amount': 0}
elif enable_amount >= 100:
# 执行卖出逻辑
order(code, -100)
# 模拟扣减可用持仓,防止重复报单
g.local_positions[code]['enable_amount'] -= 100
amount 增加,但 enable_amount(可用持仓)当天不能增加。可转债、ETF等 T+0 品种则可以同步增加 enable_amount。order 指令后到 on_trade_response 接收到主推之间,仍有微小的延迟。为了极致防重,建议在发出 order 指令的下一行代码,直接在本地缓存中提前扣减 enable_amount(即虚拟占扣),待主推到达时再进行精确对账。