🚀 AI 一键生成 ptrade 策略代码

PTrade 如何进行带底仓回测?使用 set_yesterday_position 函数模拟真实持仓

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

问题描述

如何设置一个包含初始持仓的回测策略?

解决方案

在PTrade中设置包含初始持仓的回测策略,主要通过在 initialize 函数中调用 set_yesterday_position 接口来实现。该接口允许您手动指定回测开始前的持仓状态,包括持仓数量、可用数量和持仓成本。

以下是具体的实现步骤和代码示例。

核心步骤

  1. 构建持仓列表:创建一个包含字典的列表,每个字典代表一只股票的持仓信息。
  2. 调用接口:使用 set_yesterday_position(position_list) 将持仓信息传入系统。
  3. 设置股票池:通常建议使用 set_universe 将持仓股票加入股票池,以便后续获取行情和交易。

策略代码示例

以下代码展示了如何设置“恒生电子(600570.SS)”的初始持仓,并在回测开始后卖出部分股票以验证持仓有效性。

def initialize(context):
    """
    初始化函数,设置股票池和初始持仓
    """
    # 定义我们要操作的股票
    g.security = '600570.SS'
    
    # 1. 设置股票池
    set_universe(g.security)
    
    # 2. 构建初始持仓信息
    # 格式为列表套字典,支持同时设置多只股票
    initial_positions = [
        {
            'sid': g.security,      # 标的代码
            'amount': 10000,        # 总持仓数量
            'enable_amount': 10000, # 可用数量(T+1制度下,初始持仓通常设为与总持仓相等)
            'cost_basis': 45.50     # 持仓成本价
        }
    ]
    
    # 3. 调用接口设置底仓
    # 注意:该函数仅在回测模块可用
    set_yesterday_position(initial_positions)
    
    # 设置一个标志位,用于在handle_data中演示卖出操作
    g.has_sold = False
    
    log.info("初始持仓设置完成:持有 %s 共 10000 股" % g.security)

def handle_data(context, data):
    """
    按周期运行的策略逻辑
    """
    # 演示:如果还没有卖出过,则卖出100股,验证初始持仓是否生效
    if not g.has_sold:
        # 获取当前持仓对象
        position = get_position(g.security)
        
        # 打印当前持仓信息
        log.info("当前持仓数量: %s, 可用数量: %s" % (position.amount, position.enable_amount))
        
        # 执行卖出操作
        order_id = order(g.security, -100)
        
        if order_id:
            log.info("已触发卖出100股操作")
            g.has_sold = True

参数详解

initial_positions 列表中,每个字典包含以下关键字段:

  • sid (str): 标的代码,例如 '600570.SS'
  • amount (int/float): 总持仓数量。
  • enable_amount (int/float): 可用数量。在A股T+1制度下,如果是回测开始前的老仓,通常 enable_amount 等于 amount,表示这些股票在回测第一天就可以卖出。
  • cost_basis (float): 每股的持仓成本价格,用于计算浮动盈亏。

进阶方式:从CSV文件导入

如果持仓股票较多,手动写在代码里不方便,可以使用 convert_position_from_csv 接口从上传到研究环境的CSV文件中读取配置。

CSV文件格式 (例如命名为 position.csv):

sid,amount,enable_amount,cost_basis
600570.SS,10000,10000,45.5
600000.SS,5000,5000,10.2

代码实现:

def initialize(context):
    # 从CSV文件读取持仓列表
    # 注意:文件需要先上传到研究环境的根目录或指定目录
    pos_list = convert_position_from_csv("position.csv")
    
    # 设置底仓
    set_yesterday_position(pos_list)
    
    # 提取股票代码并设置股票池
    security_list = [p['sid'] for p in pos_list]
    set_universe(security_list)

Q&A

Q: set_yesterday_position 可以在实盘交易中使用吗?
A: 不可以。该函数仅在回测模块可用。在实盘或模拟盘交易中,PTrade会自动同步柜台的实际持仓信息,无需(也不能)在策略代码中手动设置。

Q: 如果我不设置 enable_amount 会怎样?
A: 在构建字典时,enable_amount 是必须提供的字段。如果您设置 enable_amount 为 0,那么在回测的第一天,您将拥有持仓但无法卖出(相当于当天买入的股票),直到第二天才能卖出。

Q: 设置的初始持仓会影响回测的初始资金吗?
A: 不会直接扣除 context.portfolio.cash(可用资金)。set_yesterday_position 是直接在账户中“生成”股票。如果您希望保持总资产(股票+现金)恒定,您可能需要手动调整初始资金设置,或者理解为这部分股票是额外注入的资产。

Q: 为什么我在 initialize 中设置了持仓,但在 handle_data 第一天打印持仓是空的?
A: 请检查您的回测时间范围。如果回测开始日期是非交易日,或者股票在回测开始当天停牌/未上市,可能会导致数据异常。另外,请确保 set_yesterday_position 传入的格式严格为 [{}, {}] 的列表套字典格式。