🚀 AI 一键生成 ptrade 策略代码

PTrade 交易风控:策略持仓与柜台持仓同步检查机制

ptrade | 发布时间: 2025/12/23
以下内容由 EasyQuant 生成。

问题描述

如何确保策略持仓和账户实际持仓一致?

解决方案

在PTrade量化交易平台中,确保策略逻辑中的“理论持仓”与账户的“实际持仓”一致,最核心的方法是放弃记录累加式的持仓变量,转而使用“目标仓位”类交易函数

以下是详细的解决方案和代码实现。

核心机制:使用目标仓位函数

在PTrade中,不要使用 order(按数量买卖)来管理持仓,因为网络延迟、废单或手动干预会导致策略记录的数量与实际不符。

应始终使用 order_target 系列函数。这些函数的逻辑是:“无论当前持仓是多少,请通过买入或卖出,将我的持仓调整到指定的数量”。

  • order_target(security, amount):调整持仓到指定股数。
  • order_target_value(security, value):调整持仓到指定市值。
  • get_position(security):获取当前账户真实的持仓信息。

实现逻辑

  1. 获取真实持仓:每次运行逻辑时,通过 get_position 读取柜台/回测引擎的实时持仓。
  2. 计算目标:策略逻辑仅计算“我当前应该持有多少”。
  3. 自动调仓:调用 order_target,系统会自动计算(目标持仓 - 实际持仓)的差额并下单。

策略代码示例

以下代码展示了一个简单的策略:无论账户当前状态如何,策略始终确保账户持有 600570.SS 股票 1000股。如果账户为0股,它会买入1000股;如果账户已有1500股,它会自动卖出500股。

def initialize(context):
    """
    初始化函数
    """
    # 设置要操作的标的
    g.security = '600570.SS'
    set_universe(g.security)
    
    # 设定目标持仓数量
    g.target_amount = 1000

def handle_data(context, data):
    """
    盘中运行函数
    """
    # 1. 获取当前账户中该标的的实际持仓信息
    # get_position返回的是Position对象,直接读取柜台/回测账户数据
    position_info = get_position(g.security)
    
    # 获取当前持仓数量
    current_amount = position_info.amount
    
    # 2. 打印调试信息(可选)
    log.info("当前实际持仓: %s, 策略目标持仓: %s" % (current_amount, g.target_amount))
    
    # 3. 使用 order_target 确保持仓一致
    # 该函数会自动判断:
    # - 如果 current < target,则买入 (target - current)
    # - 如果 current > target,则卖出 (current - target)
    # - 如果 current == target,则不进行任何操作
    order_target(g.security, g.target_amount)
    
    # 注意:如果使用 order_target_value,则是按目标市值对齐
    # 例如:调整持仓市值到 50000 元
    # order_target_value(g.security, 50000)

def after_trading_end(context, data):
    """
    盘后处理
    """
    # 盘后再次核对
    pos = get_position(g.security)
    log.info("盘后核对持仓 - 标的: %s, 数量: %s" % (g.security, pos.amount))

关键注意事项

  1. 避免使用全局变量记录持仓
    不要在 initialize 中定义如 g.my_pos = 0 然后在交易时 g.my_pos += 100。一旦发生重启或漏单,g.my_pos 将永远错误。始终信任 get_position 返回的数据。

  2. 未成交订单(Open Orders)的影响
    order_target 计算差额时,通常基于已成交的持仓。如果此时还有未成交的挂单(Open Orders),可能会导致重复下单。

    • 解决方案:在下单前,先撤销所有未完成订单,或者检查是否有未完成订单。
    # 进阶:下单前检查未完成订单
    open_orders = get_open_orders(g.security)
    if open_orders:
        log.info("存在未完成订单,跳过本次调仓或执行撤单")
        # 可选:cancel_order(open_orders[0].id)
    else:
        order_target(g.security, g.target_amount)
    
  3. 交易频率
    如果策略是分钟级回测或交易,order_target 会在每一分钟都尝试对齐持仓。如果目标未变且持仓已对齐,API内部通常会忽略,不会产生废单,但在日志中可能会看到调用记录。

  4. 实盘同步延迟
    在实盘交易中,柜台回报可能有几秒的延迟。如果高频调用 order_target,建议在 handle_data 中加入适当的逻辑判断,避免在资金未刷新时连续发单。


Q&A

Q: 为什么我的 order_target 没有下单?
A: 可能是因为当前实际持仓已经等于目标持仓,或者资金不足、标的停牌、未达到最小交易单位(如股票不足100股)。

Q: get_position 在实盘中获取的是实时的吗?
A: 是的,get_position 在交易模式下直接读取连接的柜台账户数据。但需注意柜台数据推送本身可能存在微小的延迟(通常在秒级)。

Q: 如果我手动在软件上卖出了一半股票,策略会自动买回来吗?
A: 是的。如果策略逻辑中写的是 order_target(security, 1000),而你手动卖出导致持仓变为500,下一次策略运行 handle_data 时,会检测到持仓不足,自动买入500股以补齐到1000股。

Q: 如何清空某只股票的持仓?
A: 使用 order_target(security, 0) 即可卖出该标的的所有持仓。