问题描述
解决方案
在PTrade回测中,要通过CSV文件加载初始持仓,主要使用 convert_position_from_csv 和 set_yesterday_position 这两个API接口。
以下是详细的步骤说明和代码示例。
1. 准备CSV文件
首先,你需要确保你的CSV文件格式符合PTrade的要求。文件必须包含表头,且列名必须严格对应以下字段:
- sid: 标的代码(如
600570.SS) - amount: 总持仓数量
- enable_amount: 可用持仓数量(通常与总持仓相等,除非有冻结)
- cost_basis: 持仓成本价
CSV文件内容示例 (initial_positions.csv):
sid,enable_amount,amount,cost_basis
600570.SS,1000,1000,45.50
000001.SZ,2000,2000,12.30
注意:
- 请将该CSV文件上传至PTrade的研究(Notebook)根目录或指定文件夹下。
- 文件名不要包含特殊字符。
2. 策略代码实现
在策略的 initialize 函数中,读取该文件并设置底仓。
def initialize(context):
"""
初始化函数,设置回测参数和初始持仓
"""
# 1. 设置回测频率等基础配置
# 注意:set_yesterday_position 仅在回测模块可用
# 2. 定义CSV文件的路径
# 如果文件在研究根目录下,直接写文件名
# 如果在子文件夹下,例如 data 文件夹,则写 'data/initial_positions.csv'
csv_file_path = 'initial_positions.csv'
try:
# 3. 使用 convert_position_from_csv 读取CSV文件
# 该函数会自动解析CSV并返回符合 set_yesterday_position 要求的列表格式
pos_list = convert_position_from_csv(csv_file_path)
# 4. 打印读取到的持仓信息,方便调试查看
log.info("读取到的初始持仓列表: %s" % pos_list)
# 5. 设置底仓
# 注意:这会初始化策略的持仓对象
if pos_list:
set_yesterday_position(pos_list)
log.info("初始底仓设置成功")
else:
log.warning("CSV文件为空或读取失败,未设置底仓")
except Exception as e:
log.error("设置底仓时发生错误: %s" % e)
# 6. 设置基准(可选)
set_benchmark('000300.SS')
def handle_data(context, data):
"""
盘中运行函数
"""
# 示例:打印当前持仓以验证是否加载成功
# 仅在第一天打印一次
if context.blotter.current_dt.hour == 9 and context.blotter.current_dt.minute == 31:
positions = context.portfolio.positions
for code, pos in positions.items():
log.info("当前持仓: %s, 数量: %s, 成本: %s" % (code, pos.amount, pos.cost_basis))
3. 关键点解析
-
convert_position_from_csv(path):- 这个函数是专门为了简化从文件读取持仓而设计的。
- 它会读取CSV文件并将其转换为
set_yesterday_position所需的list[dict]格式,即[{'sid': '...', 'amount': '...', ...}, ...]。 - 路径问题:
path参数是相对于“研究”环境根目录的相对路径。
-
set_yesterday_position(poslist):- 该函数接受一个列表,列表中的每个元素是一个字典,包含股票代码、数量和成本。
- 资金影响: 该函数设置的是股票持仓。回测的初始现金(Cash)通常是在回测界面的配置参数中设置的(例如“初始资金 1,000,000”)。
set_yesterday_position创建的持仓价值会加在你的总资产(Portfolio Value)中,或者根据具体回测引擎的逻辑,它代表你“昨天”已经持有的股票。
-
适用范围:
- 这两个函数仅在回测模块(Backtest)中有效。在实盘交易模式下,持仓通常直接从柜台同步,无需手动通过CSV设置。
Q&A
Q1: 如果我的CSV文件里包含不在股票池(set_universe)里的股票,会报错吗?
A: set_yesterday_position 会建立持仓对象,即使这些股票没有显式地通过 set_universe 加入股票池,它们也会出现在 context.portfolio.positions 中。但是,为了确保后续 handle_data 能获取到这些股票的行情数据(如 data[security]),建议在 initialize 中将这些股票加入 set_universe,或者使用 set_universe(list(context.portfolio.positions.keys())) 动态添加。
Q2: convert_position_from_csv 支持 Excel (.xlsx) 文件吗?
A: 不支持。该API仅支持 CSV 格式。如果你有 Excel 文件,请先在 Excel 中将其“另存为” CSV (逗号分隔) 格式,并上传到 PTrade 研究环境中。
Q3: 设置的底仓会扣除我的初始资金吗?
A: 在 PTrade 回测中,set_yesterday_position 主要是为了模拟“继承”之前的持仓。通常情况下,它构建的是持仓部分,而回测设置里的“初始资金”指的是可用现金(Cash)。因此,你的账户总资产(Total Value) = 初始现金 + 底仓市值。它不会从初始现金中扣除购买底仓的钱,而是视为额外的资产或已存在的资产状态。
Q4: 为什么我运行代码后报错 "File not found"?
A: 这通常是因为文件路径不正确。
- 确认文件已上传到“研究”环境。
- 确认文件名大小写完全匹配。
- 如果文件在文件夹内,路径需要包含文件夹名,例如
'my_folder/position.csv'。可以使用get_research_path()查看根目录路径辅助调试。