模拟交易和实盘交易的资金、持仓无法隔离怎么办?
/
问题描述
解决方案
在 ptrade 量化交易平台中,由于券商底层的资金和持仓通常是统一计算的,如果在一个账户中同时运行模拟策略(或多个不同的实盘子策略),直接使用 context.portfolio 获取的资金和持仓数据会发生混淆。为了实现资金和持仓的有效隔离,我们需要在策略内部构建**“虚拟子账户”,并结合持久化技术(pickle)**来管理状态。
核心解决思路
- 放弃全局真实持仓:不再依赖
context.portfolio.cash和context.portfolio.positions作为交易决策的唯一依据。 - 构建虚拟子账户:在全局变量
g中定义字典来记录当前策略专属的虚拟资金(g.virtual_cash)和虚拟持仓(g.virtual_positions)。 - 利用主推事件更新状态:通过
on_trade_response(成交主推回调)来精准更新虚拟资金和持仓,确保与实际成交一致。 - 数据持久化:使用
pickle模块将虚拟账户数据落地保存,防止策略重启或服务器升级导致数据丢失。
Python 实现源码示例
以下是一个完整的代码框架,展示如何实现资金与持仓的隔离管理:
import pickle
import os
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 定义持久化文件路径
g.save_path = get_research_path() + 'virtual_account.pkl'
# 尝试加载历史虚拟账户数据
if os.path.exists(g.save_path):
try:
with open(g.save_path, 'rb') as f:
account_data = pickle.load(f)
g.virtual_cash = account_data.get('cash', 100000.0) # 默认初始资金10万
g.virtual_positions = account_data.get('positions', {})
log.info("成功加载虚拟账户数据")
except Exception as e:
log.error("加载虚拟账户失败: %s" % e)
init_virtual_account()
else:
init_virtual_account()
def init_virtual_account():
# 初始化虚拟账户
g.virtual_cash = 100000.0
g.virtual_positions = {}
save_virtual_account()
def save_virtual_account():
# 保存虚拟账户数据到本地
account_data = {
'cash': g.virtual_cash,
'positions': g.virtual_positions
}
try:
with open(g.save_path, 'wb') as f:
pickle.dump(account_data, f, -1)
except Exception as e:
log.error("保存虚拟账户失败: %s" % e)
def handle_data(context, data):
security = g.security
current_price = data[security]['close']
# 示例买入逻辑:如果虚拟资金充足,买入100股
cost = current_price * 100
if g.virtual_cash >= cost:
order(security, 100)
log.info("触发买入委托")
# 示例卖出逻辑:如果虚拟持仓中有该股票,全部卖出
virtual_amount = g.virtual_positions.get(security, 0)
if virtual_amount >= 100:
order(security, -100)
log.info("触发卖出委托")
def on_trade_response(context, trade_list):
# 接收成交主推,精准更新虚拟账户
for trade in trade_list:
# 仅处理已成状态 (status == '8')
if trade.get('status') == '8':
stock = trade['stock_code']
amount = trade['business_amount']
balance = trade['business_balance']
direction = trade['entrust_bs'] # 1-买,2-卖
if direction == '1': # 买入成交
g.virtual_cash -= balance
g.virtual_positions[stock] = g.virtual_positions.get(stock, 0) + amount
elif direction == '2': # 卖出成交
g.virtual_cash += balance
g.virtual_positions[stock] = g.virtual_positions.get(stock, 0) - amount
if g.virtual_positions[stock] <= 0:
del g.virtual_positions[stock]
log.info("虚拟账户更新 -> 资金: %.2f, 持仓: %s" % (g.virtual_cash, g.virtual_positions))
# 每次成交后持久化保存
save_virtual_account()
注意事项与优化建议
- 手续费扣除:上述示例中未包含手续费计算。在实际应用中,需要在
on_trade_response中根据券商费率(如万分之三佣金+印花税等)额外扣除g.virtual_cash中的手续费。 - 订单状态管理:除了成交主推,建议结合
on_order_response监控废单或撤单情况,避免虚拟资金被长期“冻结”。 - 多策略标识:如果在一个账户中运行多个实盘策略,可以在下单时利用
order接口返回的order_id,在全局维护一个g.my_order_ids列表。在主推回调中,只处理属于本策略的order_id,从而实现多策略间的完美隔离。