BigTrader 量化交易引擎(回测)

简介

BigTrader 是 BigQuant 推出的专业级量化交易引擎,主要用于策略在历史数据中回测撮合。BigTrader采用 C++ 核心实现,并提供 Python API 接口和回调函数。它为量化投资者提供了一个全面的交易解决方案,无论您是初学者还是专业投资者,都能轻松上手使用。

核心特性

  • 全市场覆盖

    • 多品种支持:覆盖股票、基金、期货、可转债、指数、期权、两融等主流投资品种

    • 全面的数据支持:支持从日线到逐笔成交的各类数据

  • 多场景适配

    • 回测环境:用于策略开发和历史表现分析

    • 仿真模拟:在仿真环境下进行模拟交易

    • 实盘交易:直接接入真实市场进行交易

    • 绩效分析:全方位评估策略表现

  • 多级别交易支持

    • 日频交易(日线级别)

    • 分钟级交易

    • Tick 级交易

    • 逐笔交易(Tick2)

技术优势

  • 高度还原真实交易

    • 回测环境最大程度模拟真实市场条件

    • 考虑各种交易限制和市场规则

    • 确保回测结果的可靠性和参考价值

  • 无缝代码迁移

    • 同一套代码可用于回测、模拟和实盘

    • 无需在不同环境间修改代码

    • 大幅降低策略部署成本

  • 专业工程框架

    • 结构化的策略开发环境

    • 完善的工程化支持

    • 提高策略开发效率

    • 便于团队协作和策略管理

适用人群

  • 初学者

    • 友好的 Python API 接口

    • 详细的使用文档和示例

    • 完整的策略开发流程指导

  • 专业投资者

    • 高性能 C++ 核心引擎

    • 灵活的策略定制能力

    • 专业的风控和监控体系

交易引擎介绍

BigQuant回测引擎为时间驱动回测引擎,当设定好每一根K线后,会根据K线频率读取数据。如当在回测引擎中设置为daily时,回测引擎会按照天从传入数据读取。

回测引擎交易时间图{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}

回测引擎交易时间图{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}


回测引擎运行逻辑{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}

回测引擎运行逻辑{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}{w:100}


回测引擎的运行逻辑为每一根K线运行一次,在当前K线进行下单操作时会在下一根K线开始撮合成交。


交易引擎的调取

搜索bigtrader, 拖入画布即可

可视化回测引擎

可视化回测引擎




交易引擎详细介绍

业务流程框架图:


交易所后缀

平台的各交易所代码后缀说明,均为真实交易代码+交易所后缀:


交易所

代码后缀

示例

说明

上交所 SSE

SH

600000.SH、510050.SH、000001.SH

含股票、基金、可转债、指数

深交所 SZSE

SZ

000001.SZ、159919.SZ、399001.SZ

含股票、基金、可转债、指数

北交所 BSE

BJ

920099.BJ

含股票、指数

中金所 CFFEX

CFE

IF2501.CFE, T2503.CFE, IO2501-C-4300.CFE

含股指期货、国债期货、股指期权

上期所 SHFE

SHF

rb2505.SHF, cu2503.SHF

含期货和期货期权,合约代码为小写+2位年份+2位月份

上能所 INE

INE

sc2505.SHF

含期货和期货期权,合约代码为小写+2位年份+2位月份

大商所 DCE

DCE

a2505.DCE

含期货和期货期权,合约代码为小写+2位年份+2位月份

郑商所 CZCE

CZC

SR505.CZC

含期货和期货期权,合约代码为大写+1位年份+2位月份

广期所 GFEX

GFE

si2505.GFE

含期货和期货期权,合约代码为小写+2位年份+2位月份

上交所期权 SSE

SHO

10000001.SHO


深交所期权 SZSE

SZO

90000001.SZO



策略回调函数介绍

每个策略需要实现以下一个或多个回调函数,并传给交易引擎,交易引擎会在不同的事件触发时调用对应的策略回调函数,以通知策略发生事件变化(如行情更新、委托回报通知、成交回报通知),策略的逻辑主要在 handle_data 回调函数内实现。用户可通过可视化或代码方式对函数内容进行更改,最终实现通过回测引擎达到回测的目的。以下是各类函数的运行逻辑。

函数名称

函数英文名称

说明

初始化函数

initialize(context)

策略初始化函数,只触发一次。可以在该函数中初始化一些变量,如读取配置、设置交易费率、设置交易滑点等

盘前处理函数

before_trading(context, data)

策略盘前交易函数,每日盘前触发一次。可以在该函数中处理一些当日交易前的准备,如高频回测交易时要订阅行情等

行情处理函数

handle_data(context, data)

K线行情通知函数,频率支持日线和分钟。注册多个合约时,handle_data会等待所有合约数据到齐后统一触发一次

tick处理函数

handle_tick(context, tick)

Tick快照行情通知函数,每个标的的行情有变化时则会触发,此函数的触发依赖于交易所实时行情推送。

逐笔成交处理函数

handle_l2trade(context, l2trade)

逐笔成交行情更新时的处理函数

逐笔委托处理函数

handle_l2order(context, l2order)

逐笔委托行情更新时的处理函数

委托回报通知函数

handle_order(context, order)

委托回报通知函数,每个订单状态有变化时会触发。

成交回报通知函数

handle_trade(context, trade)

成交回报通知函数,有成交时会触发。

盘后处理函数

after_trading(context, data)

盘后处理函数,每日盘后运行一次

有两个使用频率很高的函数:initialize函数和handle_data函数,理解了这两个函数开发策略就再也不是什么难事了,结合下面K线图来理解这两个函数。

初始化函数、行情处理函数原理

初始化函数、行情处理函数原理

从图中可以看出,其实一共有26个事件,即26根K线,第一根K线既对应黑色箭头,又对应灰色箭头,其余都只对应灰色箭头。Initialize函数只在第一个事件上调用,即第一根K线,因此很多初始设置可以放在Initialize函数里面。每个K线都对应灰色箭头,表示每个事件都会调用handle_data函数,即从第一根K线到最后一根K线都会运行handle_data一次,于是很多策略逻辑部分就可以放在handle_data里。

什么是策略的 context

    context是策略的上下文对象,每个策略的函数的第一个参数都是 context,必须通过此对象才能获取到策略交易相关的资产,如资金、持仓、委托等,也必须通过此对象才发完成发单的操作。context 拥有的属性和接口几以下介绍。

context 有哪些属性

  • portfolio:投资组合对象,其中包含 资金cash: float, 持仓字典positions: dict 等属性

  • user_store: 用户持久化变量的数据对象,字典类型,主要用于模拟交易,用户可以将策略需要持久化的变量写入该字典。

  • data: 用户通过回测入口传入的自定义数据(如预测/因子数据),用户传入什么数据,在策略里引用 context.data 就是什么数据。

context 有哪些接口

下单接口调用示例:context.order(instrument, 100) 或 context.order_target_percent(instrument, 0.2)

下单接口公有说明:

  • instrument: str, 平台内的标的代码,如 000001.SZ 或 rb2501.SHF 等

  • limit_price: float,默认为 None,表示使用市价单,实盘中上交所市价单时,此字段为保护价,并指定 order_type=OrderType.MARKET(市价五档即成剩撤)

  • order_type: OrderType,默认为None,表示使用市价单,当指定了 order_type 参数时,订单类型优先为指定类型,可从 bigtrader.constant 中 import

  • 下单接口返回值为 int 类型,小于0表示失败,失败时可使用 context.get_error_msg(ret_code) 获取失败的错误信息

  • 下单成功后,可以通过 context.get_last_order_key() 获取刚下单的委托的本地唯一编号,后续的委托回报均可通过 order_key 找到对应关系

接口分类

接口名称

接口说明


交易类




普通下单

order(instrument: str, order_qty: int, limit_price=None, order_type=None)

order_qty:委托数量,>0为买,<0为卖。
limit_price: 委托价格,None为默认市价单,指定价格时为限价单。


按目标量下单

order_target(instrument: str, target: int, limit_price=None, order_type=None)

target: 为目标持仓量,注意下期货订单时可以为负,表示做空至 target 手


按目标仓位下单

order_target_percent(instrument: str, percent: float, limit_price=None, order_type=None)

target: 为目标持仓占比(按账户总资产计算占比)


按目标金额下单

order_target_value(instrument: str, value: float, limit_price=None, order_type=None)



按金额下单

order_value(instrument: str, value: float, limit_price=None, order_type=None)



按仓位下单

order_percent(instrument: str, percent: float, limit_price=None, order_type=None)



买入开仓

buy_open(instrument: str, order_qty: int, limit_price=None, order_type=None)

期货/期权专用


卖出平仓

sell_close(instrument: str, order_qty: int, limit_price=None, order_type=None)

期货/期权专用


卖出开仓

sell_open(instrument: str, order_qty: int, limit_price=None, order_type=None)

期货/期权专用


买入平仓

buy_close(instrument: str, order_qty: int, limit_price=None, order_type=None)

期货/期权专用


担保品买卖

margin_trade(instrument: str, order_qty: int, limit_price=None, order_type=None)

两融专用


融资买入

margincash_open(instrument: str, order_qty: int, limit_price=None, order_type=None)

两融专用


卖券还款

margincash_close(instrument: str, order_qty: int, limit_price=None, order_type=None)

两融专用


融券卖出

marginsec_open(instrument: str, order_qty: int, limit_price=None, order_type=None)

两融专用


买券还券

marginsec_close(instrument: str, order_qty: int, limit_price=None, order_type=None)

两融专用


直接还款

margincash_direct_refund(value: float)

两融专用


直接还券

marginsec_direct_refund(instrument: str, order_qty: int)

两融专用


撤单

context.cancel_order(order_param)

order_param:可以是 order 数据,也可以 order_key,也可以 cancel_req


查询类




获取资金账户

get_trading_account() -> FundData

包含总资金,可用资金,保证金,持仓市值等


获取两融负债信息

get_marginasset_data() -> Dict

包含总资金,可用保证金,融资负债,融券负债等


获取总资金

get_balance() -> float

总资金=可用资金+冻结资金


获取可用资金

get_available_cash() -> float



获取账户总资产

get_portfolio_value() -> float

股票总资产 = 总资金 + 总持仓市值
期货总资产 = 总资金 + 总保证金 + 持仓盈亏


获取单个持仓

get_position(instrument: str, direction=None)-> PositionData

注意,获取期货的持仓时,需要传入 direction 值时,'1'获取多持仓持仓数据,'2'获取空头持仓数据,否则返回的是一个期货多空持仓的组合对象(可以通过 .long 或 .short 获取多头仓数据或空头持仓数据)


获取所有持仓

get_positions() -> Dict[key, PositionData]

使用该接口获取的持仓字典中,字典的值为期货持仓时,也是一个期货多空持仓的组合对象(可以通过 .long_position() 或 .short_position() 获取多头仓数据或空头持仓数据 PositionData)


获取当日委托

get_orders(instrument="") -> List[OrderData]

instrument 传入值时表示只获取此代码相关的委托


获取未成交委托

get_open_orders(instrument="") -> List[OrderData]

instrument 传入值时表示只获取此代码相关的挂单


获取当日成交

get_trades(instrument="") -> List[TradeData]

instrument 传入值时表示只获取此代码相关的成交


获取最新价格

get_last_price(instrument: str) -> float



获取合约信息

get_contract(instrument: str) -> ContractData

ContractData 主要有 合约大小multiplier, 最小变动价格price_tick, 合约名称name, 标的代码underlying 等属性


获取当前交易日

get_trading_day() -> str

返回当前的交易日 YYYYmmdd,夜盘时交易为第二天(周末或节假日顺延)






设置类




设置费率

from bigtrader.finance.commission import PerOrder, PerContract
set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0003, min_cost=5, tax_ratio=0.0005))
set_commission(futures_commission=PerContract(cost={"rb": (2, 2, 1), "IF": (0.000023, 0.00015, 0.000023)}))
set_commission_ratio(code: str, open_ratio: float, close_ratio: float, closetoday_ratio: float)

股票使用 PerOrder 设置费率,参数分别为 买入费率buy_cost,卖出费率sell_cost,最少费用min_cost,印花税率tax_ratio。
期货使用 PerContract 设置费率,格式为一个字典,字典的Key为品种代码,值为Tuple (开仓费率,平仓费率,平今费率)。期货也可以使用set_commission_ratio设置费率,参数 code 可以是品种代码或具体合约代码,费率值>=0.1时按手数收到,否则按金额比例收取


设置保证金率

set_margin_ratio(code: str, margin_ratio: float)

期货专用,参数 code 可以是品种代码 rb 或完全合约代码 rb2501.SHF


设置滑点

set_slippage_name("fixed") 设置为策略指定价格成交,一般可用于交割单回测set_slippage_value(slippage_type=1, slippage_value=1.0) 或者 set_slippage_value(slippage_type=2, slippage_value=0.005)

使用 set_slippage_value 时,slippage_type=1 表示固定滑点 slippage_value 的值slippage_type=2 表示滑点 slippage_value 百分比的值






其它




订阅或取消订阅行情

订阅 Tick 数据:subscribe(instruments: List[str] | str)
订阅分钟数据: subscribe_bar(instruments: List[str] | str)
取消订阅: unsubscribe(instruments: List[str] | str)

主要为订阅高频数据(分钟或Tick)行情,且做高频回测时,每日在盘前函数必须订阅策略当天所需要的代码列表的行情(注意,不需要的代码不要订阅,否则会影响性能)


是否是回测模式

is_backtest_mode() -> bool








什么是 data

如上述,多个策略回调函数的第二个参数就是 data,它是一个 IBarData 对象,封装了一些访问 Bar 数据的访问接口

data 有哪些属性:

属性名称

属性说明


data.current_dt

datetime 类型,表示回测中当前回测自然日期+时间


data.trading_day_dt

datetime类型,表示回测中当前的交易日,如期货夜盘时,current_dt为夜盘的自然日期,而交易日则是第二天的日期了





data 有哪些接口:

接口名称

接口

接口说明

获取 Bar 某字段值

current(instrument: str, field: str) -> float | int

instrument:平台内的标的代码,如 000001.SZ 或 rb2501.SHF 等
field: 为K线中的主要字段:如 open, close, volume 等

获取历史N根 Bar 的值

history(instrument: str, fields: List[str] | str, count: int, frequency: str, expect_ndarray=True)

frequency: 1d 或 1m
expect_ndarray 为 True 时会尝试返回 numpy array 数据

获取日K线的值

get_daily_value(instrument, field: str) -> float | int

instrument:平台内的标的代码,如 000001.SZ 或 rb2501.SHF 等
field: 为K线中的主要字段:如 open, close, volume 等

BigTrader 其它说明

  • 股票/基金回测/模拟交易时,如何处理除权除息:

    • 现在平台均使用复权因子来处理,即发现当天和前一天的复权因子发生变化,会得到复权因子的变化比率,来调整持仓数量和持仓价格

    • 发生除权除息后,交易引擎会生成一条成交记录,成交记录中有成交数量(转送股数量)或成交金额(分红金额)等值

  • 对于股票退市或期货合约到期的处理

    • 股票会在退市日期,按最新价格自动平仓,会生成一条平仓成交记录,成交金额返还至账户资金,成交时间为00:00:00,也会生成一条 expire 开头的日志

    • 期货会在到期日期,按最新价格自动平仓,会生成一条平仓成交记录,释放的保证金和平仓盈亏返还至账户资金,成交时间为00:00:00,也会生成一条 expire 开头的日志

  • 交易引擎的撮合逻辑:

    • 日频撮合:买入时>最低价,卖出时<最高价 则成交,成交参考价格取决于回测模块指定的 open / close,成交数量=min(委托数量,Bar的成交量*成交比例volume_limit)

    • 分钟撮合:买入时>最低价,卖出时<最高价 则成交,成交参考价格为下一分钟的 open,成交数量会依次撮合至收盘或订单完全成交

    • Tick撮合:使用盘后撮合,买入时>=卖一价,卖出时<=买一价 则成交,成交价格依次从1档到5档,直至订单全部成交

  • 日频回测时,在 handle_data 中下单,会在下一日撮合成交

    • 因为日频回测时, handle_data 已表示当天已经收盘,策略收到了当天完整的K线数据,若产生了交易信号,当天已不能交易,因为订单请求会暂存至下一天发送出去撮合

  • 回测时,当天未成交的委托会在当天盘后自动清空,不会移到下一日继续撮合。注意:日频回测当日新下的订单,不属于未成交委托,因为单子还未发到模拟撮合引擎里

  • 高频回测交易时,为什么每天都需要在 before_trading_start 回调函数里订阅行情:

    • 在回测时,由于高频数据存储在dai数据平台里,高频数据量特别大,回放行情模块需要知道当天需要回放哪些代码+什么频率的数据,数据可能分布在不同的表中,需要模拟实盘一样按时间先后排序回放行情,以最大仿真实盘中你的策略在交易时间段不停的收到一笔笔行情数据

    • 在实盘时,实时行情服务器在远端,策略需要也将策略关心的代码列表订阅发送给实时行情服务器,然后才能收到实时行情主推,比如当收到一笔Tick行情主推时,交易引擎会立即回调策略的 handle_tick(context, tick) 函数

  • 如何自定义分析回测详细交易结果:

    • 回测模拟运行完成时,会返回一个 raw_perf 是 DataFrame 类型,里面统计了每天的详细交易信号,还包括每日持仓,每日委托,每日成交

  • 如何提升你的策略代码运行效率:

    • 如果是当日静态不变的数据,可以在 before_trading 里提前准备好

    • 尽量不要在回测过程中,在 handle_data / handle_tick 里总是生成 pd.Series 或 pd.DataFrame 来做一些计算,因为它们是非常耗时的操作,建议多使用 numpy 相关接口来实现

  • 关于策略需要变量持久化的注意:

    • 变量初始化一般在 initialize() 函数里进行,但是由于模拟交易每天运行时都会再触发 initialize() 函数,因此策略应该在初始化变量时应该先判断变量名是否在 context.user_store 字典中,不存在时再设置初始值。否则可能出现在回测和模拟交易时策略触发信号的日期不一样。

    • 也可以在 initialize() 里调用 context.user_store.init_once(k1=v1, k2=v2) 方式初始化变量,内部会判断变量是否已存在,不存在会设置初始值,存在则略过。



BigTrader 的数据对象

资金数据 FundData(TradingAccount):

资金账户属性

属性含义

补充说明

account_id: str

资金账号


balance: float

总资金

可用资金 + 冻结资金

available: float

可用资金


frozen_cash: float

冻结资金


portfolio_value: float

总资产

股票=总资金+总市值期货=总资金+总保证金+持仓盈亏

total_market_value: float

总市值

股票/基金/债券/期权

total_margin: float

总保证金

期货 / 期权卖方

commission: float

当日总交易费用


positions_pnl: float

持仓盈亏


持仓数据 PositionData:

持仓属性

属性含义

补充说明

instrument: str

持仓代码


posi_direction: str

持仓方向

'1'-多头,'2'-空头

current_qty: int

持仓数量


avail_qty: int

可用数量


cost_price: float

持仓均价


today_qty: int

今仓数量


margin: float

保证金占用


last_price: float

最新价


open_date: int

开仓日期

YYYYmmdd

open_price: float

开仓均价


委托数据 OrderData:

委托属性

属性含义

补充说明

instrument: str

持仓代码


direction: Direction

持仓方向

Direction.BUY / SELL

offset_flag: OffsetFlag

开平标志

OffsetFlag.OPEN/CLOSE/CLOSETODAY

order_type: OrderType

委托类型

OrderType.LIMIT/MARKET/MARKET_FOK

order_qty: int

委托数量


filled_qty: int

成交数量


order_price: float

委托均价


order_status: OrderStatus

委托状态

见下 OrderStatus 字典

order_sysid: str

系统报单编号


order_key: str

本地唯一单号


user_id: str

操作员代码


insert_date: int

报单日期

YYYYmmdd

order_time: int

报单时间

HHMMSSmmm

trading_day: int

交易日

YYYYmmdd

status_msg: str

报单状态消息


成交数据 TradeData:

成交属性

属性含义

补充说明

instrument: str

持仓代码


direction: Direction

持仓方向

Direction.BUY / SELL

offset_flag: OffsetFlag

开平标志

OffsetFlag.OPEN/CLOSE/CLOSETODAY

trade_type: TradeType

成交类型

TradeType类型,’0’-普通成交,’1’-期权行权成交,’D’-除权除息,’E’-退市平仓,’F’-强平,‘R’-直接还款还券

filled_qty: int

成交数量


filled_price: float

成交价格


filled_money: float

成交金额


trade_id: str

成交编号


order_sysid: str

系统报单编号


order_key: str

本地唯一单号


user_id: str

操作员代码


trade_date: int

成交日期

YYYYmmdd

trade_time: int

成交时间

HHMMSSmmm

trading_day: int

交易日

YYYYmmdd

Tick 数据,股票Level1行情只有5档(Level2为10档,均3秒更新一次),期货Level1行情只有1档(500毫秒更新一次,Level2为5档,有部分交易所250毫秒更新一次)

Tick属性

属性含义

补充说明

instrument: str

持仓代码


datetime: datetime

tick日期时间


time: int

tick时间

HHMMSSmmm

last_price: float

最新价格


open_price: float

开盘价格


high_price: float

最高价格


low_price: float

最低价格


volume: int

成交量


amount: float

成交额


open_interest: int

持仓量


pre_open_interest: int

昨持仓量


pre_close: float

昨收盘


upper_limit: float

涨停价


lower_limit: float

跌停价


deal_number: int

股票成交笔数


iopv: float

基金估值


ask_volumeX

叫卖量

X: 1~10

ask_priceX

叫卖价

X: 1~10

bid_priceX

叫买价

X: 1~10

bid_volumeX

叫买量

X: 1~10


BigTrader 的数据字典

买卖方向:Direction.BUY='1',SELL='2',FinancingBuy='3',SellRepay='4',LoanSell='5',BuyRedeliver='6'

开平标志:OffsetFlag.OPEN='0',CLOSE='1',CLOSE_TODAY='2',CLOSE_YESTERDAY='3'

委托类型:OrderType.LIMIT='0',MARKET='U'

委托状态:OrderStatus

委托状态

状态值

状态说明

OrderStatus.NOTTRADED

0

未成交

PARTTRADED

1

部分成交

ALLTRADED

2

全部成交

PARTCANCELLED

3

部分撤单

CANCELLED

4

全部撤单

REJECTED

5

废单

UNKNOWN

6

未知

NOTPLACE

10

未报

PLACING

11

正报

PENDINGPLACE

12

待报

PARTPENDINGPLACE

15

部分待撤

PENDINGPLACE

16

待撤销

撮合与策略运行结果说明

订单撮合处理

本章节主要介绍基于历史行情的模拟撮合介绍,主要包括基于Bar行情、快照行情、逐笔行情撮合。支持上交所和深交所两大交易所上市的A股股票、基金、债券、期权、期货等品种。不支持新股申购、市值配售、增发申购、配股等交易。股票交易费用买入按0.03%计算,卖出按0.13%计算(其中默认包含0.1%的印花税),期货则按对应的品种费率计算,实际费率也可在回测模拟中设置。

通用规则

  • 对于没有成交的委托,或者部分成交的委托,可以撒单。当天的委托如果没有成交,收市以后自动作废,不参加下一交易日的撮合。

  • 对于市价委托,未成交部分会自动撤销(即成剩撤)。

基于Bar行情数据撮合规则

  • 成交参考价格可指定为open/close,但是一般分钟回测时,成交价为下单后的第一分钟开盘价或者在之后分钟撮合时为订单限价。

  • 成交数量最大为当次bar的成交量,日线是一般还会加一个成交率比例。

  • 委托量过大时,可能出现模拟撮合结果与真实情况严重失真的情况。

基于快照行情数据的撮合规则

主要原则是基于行情中的最新价撮合,而不是买卖盘口的价格撮合,发出订单后,使用下一笔快照行情撮合。

  • 买入

    • 如果最新成交价等于委托价,按照委托价成交。

    • 如果最新成交价低于委托价,按照最新价成交。

    • 若成交价在买一价或涨停时,不能即时成交,委托会放入撮合等待队列,并且记录当时买一量,如果阶段成交量大于买一量,可成交数量是阶段成交量和当时的买一量的差,以这种方式模拟在真实交易市场排队的情形。但未及时考虑买一上的撤单量。

    • 如果涨停板被打开,价格低于委托价,则按照现价成交。

  • 卖出

    • 如果最新成交价等于委托价,按照委托价成交

    • 如果最新价高于委托价,按照最新价撮合成交 注意,若成交价在卖一价或跌停时,不能即时成交,委托会放入撮合等待队列,并且记录当时卖一量,如果阶段成交量大于卖一量,可成交数量是阶段成交量和当时的卖一量的差,以这种方式模拟在真实交易市场排队的情形。但未及时考虑卖一上的撤单量。

    • 如果跌停板被打开,价格高于委托价,则按照现价成交。 当次成交量按两个快照之间的真实成交量计算,若成交量为0,则不成交。如果真实成交数量小于委托未成交数量,则部分成交,仅撮合真实交易的成交数量,剩余的委托仍保留在撮合队列,等待新的成交明细。因此早上集合竞价期间的报单,会在 09:25:00 进行一次撮合,或 09:30:00开始进行连续竞价撮合。

      例如:600804(鹏博士)上午开市后涨停,用户在10:10以涨停价委托买入100手,此时的成交量是51000手,涨停板上买一的单子是5000手,如果涨停板没有被打开,只有阶段成交量大于5000手时,用户的委托才等到可以成交。如果成交量到了56010手,则用户成交10手(56010-51000-5000),剩下的部分等待更多的成量。

基于逐笔成交数据的撮合规则

主要原则是基于逐笔行情中的最新成交价撮合,发出订单后,使用下一笔逐笔行情撮合,需要配合当前快照盘口信息(会在收到委托时,获取当前盘口)。

  • 买入委托

    • 市价委托

      • 当前在涨停版上,不成交,自动撤销

      • 成交,即成剩余,成交量也依次从卖一到卖五档

      • 不支持FOK

    • 委托价格 > 最新价:

      • 成交,成交价=最新价,成交量依次从卖一到卖十档,生成多笔成交信息,FIXME:如果超出卖十档的处理,其中价格触发到涨停板的处理。

    • 委托价格 == 最新价

      • 成交类型主动卖,判断当前记录的排队数量,排队数量 <= 0,则成交,成交量为当次逐笔成交量,FIXME: 更逼真模式是取 逐笔成交-排队数量

      • 成交类型主动买,不成交

    • 撤单成交(仅适用于深交所)

      • 撤单价格 == 买一价,对订单队列中的买入委托的排队数量做减少

      • 其它撤单,不做处理

      • 其它不成交

  • 卖出委托:

    • 市价委托:

      • 当前在跌停版上,不成交,自动撤销

      • 成交,即成剩余,成交量也依次从买一到买五档

      • 不支持FOK

    • 委托价格 < 最新价:

      • 成交,成交价=最新价,成交量依次从买一到买十档,生成多笔成交信息,FIXME:如果超出买十档的处理,其中价格触发到跌停板的处理。

    • 委托价格 == 最新价:

      • 成交类型主动买,判断当前记录的排队数量,排队数量 <= 0,则成交,成交量为当次逐笔成交量,FIXME: 更逼真模式是取 逐笔成交-排队数量

      • 成交类型主动卖,不成交

    • 撤单成交(仅适用于深交所)

      • 撤单价格 == 卖一价,对订单队列中的买入委托的排队数量做减少

      • 其它撤单,不做处理 其它不成交


回测结果分析

当我们完成一个策略回测时,我们会得到如下的一个图形:



上图为策略回测结果图,红色矩形标记部分包含了策略的主要信息,包括 收益概况、交易详情、每日持仓及收益、输出日志 。接下来,我们详细介绍这几个部分。

收益概况

收益概况以折线图的方式显示了策略在时间序列上的收益率,黄色曲线为策略收益率。同时也显示了沪深300收益率曲线作为比较基准,蓝色曲线为基准收益率。同时,最下面的绿色曲线为持仓占比,持仓占比即仓位,10%的持仓占比表示账户里股票价值只占10%。相对收益率的曲线并没有直接绘制在图上,点击图例 相对收益率,就可以将其绘制出来。

不仅如此,衡量一个策略好坏的关键指标在收益概览页面也得到展示。

  • 收益率:策略整个回测时间段上的总收益率。比如,如果收益率为30%,表明起始时间是1万的本金,结束时间本金就变成1.3万了,一共赚了3000元。

  • 年化收益率:该策略每一年的收益率。比如,如果回测时间段为2年,总收益率为30%,那么每年的年化收益率就在15附近(不考虑复利)。

  • 基准收益率:策略需要有一个比较基准,比较基准为沪深300。若基准收益率为15%,表明在整个回测时间段,大盘本身就上涨了15%,如果策略收益率小于基准收益率,说明策略表现并不好,连大盘都没有跑赢。

  • 阿尔法:衡量策略的一个重要指标,该值越大越好。

  • 贝塔:衡量策略的一个重要指标,该值越小越好。

  • 夏普比率:衡量策略最重要的一个指标,该指标的计算不仅考虑收益率,还考虑了风险,因此比较具有参考价值,可以理解为经过风险调整后的收益率。

  • 胜率:衡量策略盈利一指标,胜率越大越好。比如10次投资中有8次获利,胜率就是80%。

  • 盈亏比:衡量策略盈亏能力大小比较,盈亏比越大越好。比如投资盈利时,平均每次盈利4元,亏损时,平均每次亏损2元,那么此时的盈亏比为2。

  • 收益波动率:收益率的标准差,是风险的一个指标。

  • 最大回撤:策略在整个时间段上亏损最严重的时候相比净值最高值下跌的百分比。如果最大回撤为20%,表明策略在某个时间点上,相比之前的净值最高点下降了20%。最大回撤是策略评估时非常关键的一个指标,通常与风险承受能力相关。

  • 信息比率:信息比率也是一个常用的策略评价指标


    关于回测结果和指标更详细的分析可参照链接:策略回测结果指标详解


交易详情

交易详情主要显示了策略在整个回测过程中每个交易日的买卖信息。包括买卖时间、股票代码、交易方向、交易数量、成交价格、交易成本。具体见下图:


每日持仓及收益

每日持仓及收益主要呈现每日持有股票代码、当日收盘价、持仓股票数量、持仓金额、收益等指标。具体见下图: