期货专用与定时任务

前面几章覆盖了股票主流程。本章讲两类进阶内容:一是期货的专用 API(开平仓、合约查询、保证金与手续费设置),二是定时任务和 tick 级处理(run_daily / run_interval / tick_data / set_parameters),它们是日内和套利策略的核心工具。

一、期货交易函数

A 股只能做多,期货天然双向。PTrade 用四个函数对应「开仓 / 平仓」×「多 / 空」:

函数含义方向
buy_open(contract, amount, limit_price=None)买入开仓做多建仓
sell_close(contract, amount, limit_price=None, close_today=False)卖出平仓平多头
sell_open(contract, amount, limit_price=None)卖出开仓做空建仓
buy_close(contract, amount, limit_price=None, close_today=False)买入平仓平空头
  • amount 均为正数(手数)。
  • close_today:仅上海期货交易所生效,True 仅平今仓;其他交易所不要传 True,否则会被强制转为 False
  • 不传 limit_price 时以行情快照最新价(交易)或分钟最新价(回测)报单。
def handle_data(context, data):
    # 开 1 手多仓
    buy_open('IF2312.CCFX', 1)
    # 平 1 手空仓
    buy_close('IF2312.CCFX', 1)
    # 做空 1 手
    sell_open('IF2312.CCFX', 1)
    # 平 1 手多仓(上期所可指定仅平今)
    sell_close('CU2312.SHF', 1, close_today=True)

二、期货合约查询

函数含义
get_instruments(contract)合约详情:乘数、交易单位、交割日、上市日、保证金、涨跌幅、最小变动价位
get_dominant_contract(contract, date=None)连续合约对应的主力合约代码
get_margin_rate(transaction_code)用户设置的保证金比例(仅回测)
# 取 IF 当前主力合约
main = get_dominant_contract('IF888.CCFX')['IF888.CCFX']['corr_month_code']
log.info('IF 主力合约:%s' % main)

# 查合约详情
info = get_instruments('IF2312.CCFX')
log.info('乘数 %s,保证金 %s' % (info['contract_multiplier'], info['margin_rate']))

回测中建议用连续合约代码(如 IF888.CCFX)做信号,再用 get_dominant_contract 映射到具体月合约下单;实盘要换成当日上市的具体合约。合约详情 API 依赖期货资料数据权限,无权限返回空 dict。

三、期货回测设置

函数含义示例
set_margin_rate(code, rate)设置保证金比例set_margin_rate('IF', 0.08)
set_future_commission(code, commission)设置手续费set_future_commission('IF', 0.00004)

股指期货按成交额比例收(如 0.4/万 = 0.00004),国债期货按每手金额收(如 2 元/手 = 2)。两者都仅在回测可用,实盘按真实柜台费率。

四、期货双均线示例

import numpy as np

def initialize(context):
    g.target = 'IF'
    g.security = g.target + '888.CCFX'   # 连续合约
    g.amount = 1
    if not is_trade():
        set_limit_mode('UNLIMITED')
        set_margin_rate(g.target, 0.15)

def before_trading_start(context, data):
    h = get_history(20, '1d', 'close', g.security, fq='dypre',
                    include=False, is_dict=True)
    g.close = h[g.security]['close']

def handle_data(context, data):
    price = data[g.security].close
    close = np.concatenate((g.close, [price]))
    ma5, ma10 = close[-5:].mean(), close[-10:].mean()
    pos = get_position(g.security)

    if ma5 > ma10:
        if pos.long_amount == 0:
            buy_open(g.security, g.amount)          # 开多
        if pos.short_amount != 0:
            buy_close(g.security, g.amount)         # 平空
    elif ma5 < ma10:
        if pos.short_amount == 0:
            sell_open(g.security, g.amount)         # 开空
        if pos.long_amount != 0:
            sell_close(g.security, g.amount)        # 平多

要点:期货持仓对象把多头和空头分开(long_amount / short_amount / long_enable_amount / short_enable_amount),判断时要分别看。

五、定时任务:run_daily

run_daily(context, func, time='9:31')
  • 只能在 initialize 中调用,可多次调用注册多个定时任务。
  • func 须以 context 为唯一参数。
  • 分钟回测中 time 须在 9:3111:30、13:0015:00;日回测无论设何值都在 15:00 执行;交易中范围 00:00~23:59。
def initialize(context):
    g.security = '600570.SS'
    set_universe(g.security)
    run_daily(context, get_data, time='9:25')     # 盘前取数据
    run_daily(context, clear_pos, time='14:55')   # 尾盘清仓

def get_data(context):
    snap = get_snapshot(g.security)
    log.info(snap)

def clear_pos(context):
    if get_position(g.security).enable_amount > 0:
        order_target(g.security, 0)

def handle_data(context, data):
    pass

六、定时任务:run_interval

run_interval(context, func, seconds=10)
  • 仅交易可用,在 initialize 中注册。
  • 非交易时段(9:3011:30、13:0015:00 之外)不执行。
  • 期货最小 1 秒,其他品种最小 3 秒。
  • run_daily + run_interval 累计线程数上限 5,超过会堵塞丢任务。
def initialize(context):
    g.security = '600570.SS'
    set_universe(g.security)
    run_interval(context, on_tick, seconds=3)

def on_tick(context):
    snap = get_snapshot(g.security)
    last = snap[g.security]['last_px']
    log.info('最新价 %s' % last)

def handle_data(context, data):
    pass

七、tick_data 事件

tick_data(context, data) 每 3 秒触发一次(9:30~14:59),data 是字典,含 tick / order(逐笔委托)/ transaction(逐笔成交)三项,后两项需开通 Level-2 行情。

import ast
def tick_data(context, data):
    sec = g.security
    bid1 = ast.literal_eval(data[sec]['tick']['bid_grp'][0])[1][0]   # 买一价
    if bid1 > 38.19:
        order_tick(sec, 100, '1')   # 以买一档下单

def handle_data(context, data):
    pass

tick_data 里的 datahandle_data 里的 data 结构不同,不要混用。

八、策略配置:set_parameters

set_parameters(not_restart_trade='1', server_restart_not_do_before='1', ...)

仅交易可用,用于控制引擎行为。关键参数:

参数含义
not_restart_trade交易时段服务器重启时是否自动重拉交易,'1' 不重拉
server_restart_not_do_before重启重拉后是否跳过重复执行 before_trading_start'1' 跳过
holiday_not_do_before节假日是否执行 before_trading_start'1' 不执行
tick_data_no_l2tick_data 的 data 是否剔除 order/transaction,'1' 剔除
receive_other_response是否接收非本交易的主推,'1' 接收
def initialize(context):
    g.security = '600570.SS'
    set_universe(g.security)
    set_parameters(not_restart_trade='1', server_restart_not_do_before='1')

取消设置:再次调用并传 '0'

九、消息通知

函数含义
set_email_info(email_address, smtp_code, email_subject)设置异常终止通知邮箱(仅 QQ 邮箱)
send_email(send_email_info, get_email_info, smtp_code, info='', ...)主动发邮件
send_qywx(corp_id, secret, agent_id, info='', ...)发企业微信消息

策略出错终止时引擎可自动发邮件提醒,对无人值守的实盘很有用。

小结

  • 期货四件套:buy_open / sell_close / sell_open / buy_close,对应多空开平;用连续合约做信号、主力合约下单。
  • 定时任务用 run_daily(固定时刻)和 run_interval(固定间隔),线程上限 5;tick 级用 tick_data 事件。
  • set_parameters 控制重启、节假日、主推等引擎行为,让策略在实盘更稳。至此 PTrade 手册从机制、框架、函数、两融、回测、示例到进阶形成闭环——左侧导航可随时回查。