问题描述
解决方案
在 PTrade 量化交易平台中,策略的运行是基于事件驱动的框架。整个策略的生命周期主要由 initialize、before_trading_start、handle_data 和 after_trading_end 这四个核心函数构成。
以下是这四个函数的详细解释、运行时间及推荐用途:
1. initialize(context) —— 初始化函数
这是策略的起点,用于定义全局变量和设置策略的基础环境。
- 运行时间:
- 回测/实盘:策略启动时只运行一次。
- 主要用途:
- 设置股票池:使用
set_universe设定需要关注的标的。 - 定义全局变量:初始化全局对象
g中的变量(如g.security,g.count等),这些变量可以在其他函数中被调用和修改。 - 设置回测参数:如设置基准 (
set_benchmark)、佣金 (set_commission)、滑点 (set_slippage) 等(仅回测有效)。 - 注册定时任务:使用
run_daily或run_interval注册非默认频率的定时任务。
- 设置股票池:使用
- 注意事项:
- 不要在此处获取动态行情数据(如
get_price),因为此时策略尚未开始推进时间。 - 禁止在此处调用
get_index_stocks(建议在before_trading_start中调用)。
- 不要在此处获取动态行情数据(如
2. before_trading_start(context, data) —— 盘前处理函数
用于在每日开盘前进行数据准备和信号过滤。
- 运行时间:
- 回测:每个交易日的 08:30。
- 实盘:每个交易日的 09:10(默认),或策略启动时立即执行一次。
- 主要用途:
- 更新股票池:根据最新数据(如指数成分股调整)更新
set_universe。 - 获取静态数据:查询财务数据 (
get_fundamentals)、历史行情 (get_history) 等。 - 过滤标的:剔除 ST 股、停牌股、退市股(使用
filter_stock_by_status)。 - 重置每日变量:将需要每日清零的计数器或标志位重置。
- 更新股票池:根据最新数据(如指数成分股调整)更新
- 注意事项:
- 在此阶段无法获取当天的实时行情(因为还没开盘)。
3. handle_data(context, data) —— 核心交易函数
这是策略的“大脑”,用于执行具体的交易逻辑。
- 运行时间:
- 按频率触发:根据策略设置的频率(日线或分钟线)周期性运行。
- 日线回测:每个交易日的 15:00。
- 日线实盘:通常为尾盘固定时间(如 14:50,具体视券商配置而定)。
- 分钟回测:交易时段内(09:31 - 15:00)的每一分钟。
- 分钟实盘:交易时段内(09:30 - 14:59)的每一分钟。
- 主要用途:
- 获取实时行情:从
data对象或get_snapshot获取当前价格、成交量等。 - 计算技术指标:调用
get_MACD、get_RSI或自行计算均线等指标。 - 生成交易信号:判断买入或卖出条件(如金叉买入、死叉卖出)。
- 执行下单:调用
order、order_target、order_value等接口进行买卖操作。
- 获取实时行情:从
- 注意事项:
- 非交易日不会触发此函数。
- Tick 级别的策略应使用
tick_data函数,而不是handle_data。
4. after_trading_end(context, data) —— 盘后处理函数
用于每日收盘后的总结、数据整理或清理工作。
- 运行时间:
- 回测/实盘:每个交易日收盘后,通常为 15:30。
- 主要用途:
- 日志记录:打印当天的持仓情况、总资产变化等。
- 数据导出:将当天的交易记录或计算结果保存到文件(如
get_trades_file)。 - 收盘结算:计算当日收益率,分析策略表现。
- 注意事项:
- 此时已无法进行交易委托。
总结流程图
为了方便理解,可以将一天的运行流程总结如下:
- 策略启动 $\rightarrow$
initialize(只运行一次) - 进入交易日循环:
- 08:30/09:10 $\rightarrow$
before_trading_start(准备数据) - 09:30 ~ 15:00 $\rightarrow$
handle_data(循环运行:看行情、算指标、下单) - 15:30 $\rightarrow$
after_trading_end(收盘总结)
- 08:30/09:10 $\rightarrow$
- 日期+1 $\rightarrow$ 重复步骤 2,直到回测结束或实盘停止。
Q&A 常见问题解答
Q: 我可以在 initialize 里下单买股票吗?
A: 不可以。initialize 运行时市场尚未开启,且该函数主要用于环境初始化。下单操作必须在 handle_data(盘中)或 after_trading_order(盘后固定价交易)中进行。
Q: 为什么建议在 before_trading_start 中获取财务数据而不是 handle_data?
A: 财务数据(如市盈率、净利润)通常按季度更新,且在盘中不会变化。在 before_trading_start 中获取可以减少盘中 handle_data 的计算压力,提高策略运行效率,特别是在分钟级策略中。
Q: handle_data 中的 data 参数有什么用?
A: data 参数包含了当前周期(分钟或日)的行情数据。例如,使用 data['600570.SS']['close'] 可以快速获取恒生电子的当前收盘价(或最新价),比调用 get_price 更高效。
Q: 如果我想在每天 10:00 固定交易,应该写在哪里?
A: 你可以在 initialize 中使用 run_daily(context, my_trade_func, time='10:00') 来注册一个定时任务。这样系统会在每天 10:00 自动调用你自定义的 my_trade_func 函数,而不需要在 handle_data 里写复杂的判断逻辑。