问题描述
解决方案
在PTrade中设置包含初始持仓的回测策略,主要通过在 initialize 函数中调用 set_yesterday_position 接口来实现。该接口允许您手动指定回测开始前的持仓状态,包括持仓数量、可用数量和持仓成本。
以下是具体的实现步骤和代码示例。
核心步骤
- 构建持仓列表:创建一个包含字典的列表,每个字典代表一只股票的持仓信息。
- 调用接口:使用
set_yesterday_position(position_list)将持仓信息传入系统。 - 设置股票池:通常建议使用
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 传入的格式严格为 [{}, {}] 的列表套字典格式。