问题描述
模拟交易和实盘交易的资金、持仓无法隔离怎么办?
解决方案
问题分析
在 ptrade 量化平台中,如果您发现模拟交易和实盘交易的资金、持仓数据发生了混淆或无法隔离,通常是因为以下原因导致的:
- 持久化文件冲突:策略中使用了
pickle等方式将自定义的持仓、资金或状态变量保存到本地文件中,但模拟盘和实盘使用了相同的文件名和路径,导致数据互相覆盖和读取。 - 全局变量污染:在某些特殊部署环境下,如果模拟和实盘共用同一个策略实例(较少见),全局变量
g可能会发生混淆。
解决方案
为了彻底隔离模拟交易和实盘交易的数据,最有效的方法是利用 ptrade 提供的 get_user_name() 接口获取当前登录的资金账号,并根据资金账号来区分逻辑和持久化文件。
1. 动态生成持久化文件路径
在保存和读取 pickle 文件时,将资金账号作为文件名的一部分,确保模拟账户和实盘账户读写不同的文件。
import pickle
from collections import defaultdict
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 获取当前登录的资金账号
g.user_name = get_user_name()
if g.user_name is None:
g.user_name = "default_account"
# 根据资金账号动态生成持久化文件路径
g.file_path = get_research_path() + f'hold_days_{g.user_name}.pkl'
# 尝试加载对应账户的持久化数据
try:
with open(g.file_path, 'rb') as f:
g.hold_days = pickle.load(f)
log.info(f"成功加载账户 {g.user_name} 的持久化数据")
except:
g.hold_days = defaultdict(list)
log.info(f"初始化账户 {g.user_name} 的空持久化数据")
def handle_data(context, data):
# 交易逻辑...
# 每天将存储状态的字典对象进行 pickle 保存,隔离到对应账户的文件中
with open(g.file_path, 'wb') as f:
pickle.dump(g.hold_days, f, -1)
2. 根据账户执行不同逻辑
如果您希望在同一个策略代码中,针对模拟盘和实盘设置不同的参数(例如交易数量、风控阈值),同样可以使用 get_user_name() 进行分支判断。
def initialize(context):
g.security = "600570.SS"
set_universe(g.security)
g.user_name = get_user_name()
# 假设 '123456789' 是实盘账号,'987654321' 是模拟账号
if g.user_name == "123456789":
g.trade_amount = 1000 # 实盘交易量
log.info("当前为实盘环境")
else:
g.trade_amount = 100 # 模拟盘交易量
log.info("当前为模拟盘环境")
def handle_data(context, data):
# 使用区分后的参数进行交易
order(g.security, g.trade_amount)
注意事项
get_user_name()的返回值:该接口在查询失败时会返回None。在编写代码时,务必做好None值的异常处理,避免拼接字符串时报错。- 框架自带的 Context 对象:ptrade 框架底层的
context.portfolio(账户资金和持仓信息)本身就是与登录的资金账号强绑定的,框架层面已经做好了隔离。您只需要确保您自己编写的持久化逻辑和自定义状态变量不发生冲突即可。 - 回测环境兼容:在回测环境中,
get_user_name()可能返回特定的回测标识或None,请确保您的路径生成逻辑在回测中也能正常运行。