策略开发API
米筐策略采用事件驱动模型:平台在特定时机(初始化、每个 bar、每日开盘前)自动调用你定义的同名函数,你在函数里写交易逻辑。本章把策略骨架拆成三部分:事件回调、context 对象、scheduler 定时器。
一、事件回调函数
你的策略必须实现 init 和 handle_bar,其余为可选:
| 函数 | 是否必须 | 触发时机 |
|---|---|---|
init(context) | 必须 | 回测/模拟开始时执行一次 |
handle_bar(context, bar_dict) | 必须 | 每个 bar(日线/分钟线)更新时 |
before_trading(context) | 可选 | 每日开盘前(期货夜盘可能前一晚触发) |
after_trading(context) | 可选 | 每日收盘后(模拟中约 15:30) |
open_auction(context, bar_dict) | 可选 | 盘前集合竞价阶段,订单按开盘价撮合 |
handle_tick(context, tick) | 可选 | 已订阅合约的 tick 更新时(tick 级回测) |
一个典型的多函数骨架:
def init(context):
context.s1 = '000001.XSHE'
context.counter = 0
def before_trading(context):
# 盘前获取财务数据、更新股票池
context.fundamentals = get_factor(context.s1, ['pe_ratio', 'revenue'])
def handle_bar(context, bar_dict):
context.counter += 1
if context.counter == 1:
order_shares(context.s1, 1000)
def after_trading(context):
logger.info('今日收盘,现金:%r' % context.portfolio.cash)
二、context 上下文对象
context 是贯穿整个策略的全局变量,用点号 . 存取自定义属性,也承载平台内置属性:
def init(context):
context.cash_limit = 5000 # 自定义属性,任意命名
context.s1 = '000001.XSHE'
内置属性一览:
| 属性 | 含义 |
|---|---|
context.now | 当前 bar 的时间点(datetime) |
context.portfolio | 投资组合信息(总权益、现金、仓位、收益率) |
context.stock_account | 股票子账户(现金、仓位) |
context.future_account | 期货子账户(现金、仓位) |
context.run_info | 策略运行配置(频率、起止日期、撮合方式等) |
context.universe | 当前合约池(随 update_universe / subscribe 更新) |
def handle_bar(context, bar_dict):
# 读取当前总权益和可用现金
total = context.portfolio.total_value
cash = context.portfolio.cash
logger.info('总权益 %.2f,可用现金 %.2f' % (total, cash))
context.portfolio在混合策略中是股票与期货子账户的汇总;单一品种策略则直接对应股票或期货投资组合。
三、scheduler 定时器
很多策略不需要每个 bar 都交易,而是「每天开盘后 10 分钟」或「每月第一个交易日」调仓。这时用 scheduler,它只能在 init 中注册:
def log_cash(context, bar_dict):
logger.info('剩余现金:%r' % context.portfolio.cash)
def init(context):
scheduler.run_daily(log_cash) # 每天运行
scheduler.run_weekly(log_cash, weekday=2) # 每周二运行
scheduler.run_monthly(rebalance, tradingday=1) # 每月第一个交易日
scheduler 函数必须接收 context 和 bar_dict 两个参数。
精确定时(分钟级)
配合 time_rule 可在分钟回测中精确到具体时分:
from rqalpha_plus.apis import market_open, market_close
def init(context):
# 每天开盘后 10 分钟(即 9:41)运行
scheduler.run_daily(my_func, time_rule=market_open(minute=10))
# 每周最后一个交易日收盘前 1 小时运行
scheduler.run_weekly(my_func, tradingday=-1, time_rule=market_close(hour=1))
market_open(hour, minute):开盘后第几小时几分,分钟范围[0, 239]。market_close(hour, minute):收盘前第几小时几分。time_rule='before_trading':盘前运行(在before_trading之后、handle_bar之前)。
time_rule仅在分钟级回测和模拟交易中生效;日回测中只保证当天运行,无法精确到时分。
四、合约池与订阅
handle_bar 的触发依赖于合约池中的合约交易时间。策略创建时已包含的品种会自动触发,但你也可以动态管理:
def init(context):
subscribe('IF1612') # 订阅期货合约行情
update_universe(['000001.XSHE', '600000.XSHG']) # 重置股票池
def handle_bar(context, bar_dict):
unsubscribe('IF1612') # 取消订阅
subscribe(id):订阅行情,合约池新增该合约。unsubscribe(id):取消订阅,合约池移除该合约。update_universe(ids):直接覆盖合约池。
单一期货策略必须在
init中subscribe有效合约,否则handle_bar不会触发;由于期货有到期日,需保证回测期间始终有活跃合约被订阅。
小结
- 策略骨架 =
init+handle_bar+ 可选的盘前盘后钩子。 context承载自定义变量和portfolio/stock_account等内置属性。scheduler.run_daily/weekly/monthly+time_rule实现定时调仓。subscribe/update_universe动态管理合约池。
骨架搭好后,下一步学习如何取数据:数据API。