3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
将回测表现良好的策略迁移至PTrade实盘环境是一个关键步骤。回测环境是理想化的(无滑点、无延迟、数据完美),而实盘环境充满了不确定性。
以下是您在上线实盘前必须注意的问题及需要修改的代码清单。
回测中常用的设置函数在实盘中是无效甚至有害的。您应当使用 is_trade() 函数来区分回测和实盘逻辑。
需要修改的地方:
set_commission(设置佣金)、set_slippage(设置滑点)、set_volume_ratio(成交比例)等函数仅在回测有效。实盘中,费率由券商决定,滑点由市场决定。def initialize(context):
# 设置股票池等通用逻辑
g.security = '600570.SS'
set_universe(g.security)
# --- 仅在回测模式下执行的设置 ---
if not is_trade():
set_commission(commission_ratio=0.0003, min_commission=5.0)
set_slippage(slippage=0.0)
set_volume_ratio(volume_ratio=0.25)
# --- 仅在实盘模式下执行的设置 ---
if is_trade():
# 可以在这里检查登录的账号是否正确
user_name = get_user_name()
if user_name != "您的资金账号":
log.error("账号不匹配,策略停止运行")
# 可以抛出异常终止策略
# raise Exception("Account Mismatch")
回测通常使用 data[security]['close'] 或 get_history 获取价格,但在实盘中,为了获取最新的毫秒级数据,建议使用 get_snapshot(行情快照)。
注意:get_snapshot 不支持回测,必须用 is_trade() 隔开。
def handle_data(context, data):
current_price = 0
if is_trade():
# 实盘:使用快照获取最新tick价格,更实时
snapshot = get_snapshot(g.security)
if snapshot:
current_price = snapshot[g.security]['last_px']
else:
# 回测:使用bar数据
current_price = data[g.security]['close']
log.info("当前价格: %s" % current_price)
# 后续交易逻辑...
问题:实盘服务器可能会在盘中重启,或者策略因异常中断后重启。一旦重启,initialize 会重新运行,内存中的全局变量 g 会被重置,导致策略丢失之前的状态(如“持仓天数”、“最高价记录”等)。
解决方案:使用 pickle 模块将关键变量保存到磁盘。
import pickle
import os
def initialize(context):
g.security = '600570.SS'
set_universe(g.security)
# 定义需要持久化的变量名
g.hold_days = 0
# 实盘启动时尝试恢复数据
if is_trade():
recover_data()
def handle_data(context, data):
# 策略逻辑...
g.hold_days += 1
# 每次关键数据变化后,保存数据
if is_trade():
save_data()
# --- 持久化辅助函数 ---
def save_data():
# 获取研究目录路径
path = get_research_path() + 'strategy_state.pkl'
# 将需要保存的变量放入字典
state = {'hold_days': g.hold_days}
try:
with open(path, 'wb') as f:
pickle.dump(state, f)
except Exception as e:
log.error("数据保存失败: %s" % e)
def recover_data():
path = get_research_path() + 'strategy_state.pkl'
if not os.path.exists(path):
return
try:
with open(path, 'rb') as f:
state = pickle.load(f)
# 恢复变量
if 'hold_days' in state:
g.hold_days = state['hold_days']
log.info("数据恢复成功: %s" % state)
except Exception as e:
log.error("数据恢复失败: %s" % e)
避免市价单(Market Order):
order(..., limit_price=...),或者使用带有保护限价的市价委托 order_market(科创板/创业板必须注意价格笼子)。防止重复下单:
get_open_orders()(未完成订单)。def handle_data(context, data):
# 检查是否有未完成的订单
open_orders = get_open_orders(g.security)
if open_orders:
log.info("存在未完成订单,跳过本次信号")
return
# 获取当前持仓
position = get_position(g.security)
# 只有在无持仓且无未完成订单时才买入
if position.amount == 0:
order(g.security, 100)
涨跌停处理:
check_limit(security) 检查涨跌停状态,避免无效报单。异常捕获:
try...except 包裹核心逻辑,防止策略直接崩溃停止。def handle_data(context, data):
try:
# 核心策略逻辑
pass
except Exception as e:
log.error("策略运行异常: %s" % e)
# 可选:发送邮件通知
# if is_trade():
# set_email_info(...)
在 initialize 中,针对实盘环境,建议设置以下参数以避免服务器重启带来的副作用:
def initialize(context):
# ... 其他初始化代码 ...
if is_trade():
# not_restart_trade="1": 交易时间段若服务器重启,不自动重新拉起本交易(防止重复执行初始化逻辑导致状态重置)
# server_restart_not_do_before="1": 服务器重启导致重拉交易时,不重复执行before_trading_start
set_parameters(not_restart_trade="1", server_restart_not_do_before="1")
在点击“开始交易”之前,请核对以下清单:
set_commission 等回测专用函数?get_snapshot 获取最新价格?pickle 保存和恢复 g 变量,以应对服务器重启?try...except 异常捕获?not_restart_trade?Q: 为什么我的实盘策略在9:30之前就报错了?
A: 实盘中 before_trading_start 可能会在9:00左右运行。如果在该函数中调用了需要开盘后才有的数据(如实时行情),可能会报错。建议在 before_trading_start 中只做静态数据初始化,或加上时间判断。
Q: 回测收益很高,实盘为什么不成交?
A: 常见原因包括:1. 价格设置不合理(如买单价格低于卖一价);2. 股票处于涨跌停状态;3. 委托数量不满足最小交易单位(如不足100股);4. 资金不足(回测可能未严格计算滑点和费率)。
Q: 如何在盘中查看策略的运行日志?
A: 在PTrade客户端的“交易”界面,找到运行中的策略,点击“日志”选项卡。建议在代码中多使用 log.info() 打印关键变量(如信号触发时的价格、持仓量),便于排查问题。
Q: get_snapshot 和 data 里的数据有什么区别?
A: data (在 handle_data 中) 通常是基于Bar(分钟线)的数据,或者是推送过来的切片数据。get_snapshot 是主动向柜台/行情服务器请求当前的最新快照。在实盘高频或对价格敏感的策略中,get_snapshot 的时效性通常更好。