策略开发API

米筐策略采用事件驱动模型:平台在特定时机(初始化、每个 bar、每日开盘前)自动调用你定义的同名函数,你在函数里写交易逻辑。本章把策略骨架拆成三部分:事件回调、context 对象、scheduler 定时器。

一、事件回调函数

你的策略必须实现 inithandle_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 函数必须接收 contextbar_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):直接覆盖合约池。

单一期货策略必须在 initsubscribe 有效合约,否则 handle_bar 不会触发;由于期货有到期日,需保证回测期间始终有活跃合约被订阅。

小结

  • 策略骨架 = init + handle_bar + 可选的盘前盘后钩子。
  • context 承载自定义变量和 portfolio / stock_account 等内置属性。
  • scheduler.run_daily/weekly/monthly + time_rule 实现定时调仓。
  • subscribe / update_universe 动态管理合约池。

骨架搭好后,下一步学习如何取数据:数据API