回测插件
回测插件基于 DolphinDB 模拟撮合功能进行订单撮合,可以基于逐笔数据或快照行情数据进行高频策略回测。
在插件市场安装插件
版本要求
- DolphinDB Server: 2.00.12 及更高版本(例如 3.00.00)
- 具有 DolphinDB 商用版 license
安装步骤
在 DolphinDB 客户端中使用
listRemotePlugins
命令查看插件仓库中的插件信息。login("admin", "123456") listRemotePlugins()
使用
installPlugin
命令完成插件安装。installPlugin("Backtest")
使用
loadPlugin
命令加载插件。loadPlugin("Backtest")
用户配置模块
用户可以配置回测的开始和结束日期,初始资金,手续费和印花税,订单的撮合模式。
key | 说明 | 备注 |
---|---|---|
"startDate" | 开始日期 | |
"endDate" | 结束日期 | |
"strategyGroup" | 策略类型 | 暂时固定股票:"stock" |
"cash" | 初始资金 | |
"commission" | 手续费 | |
"tax" | 印花税 | |
"dataType" | 行情类型:0:逐笔 + 快照 1:快照 2:快照 + 成交 3: 分钟频率 4:日频 | frequency>0 and dataType=0 时,行情为逐笔行情,引擎内部合成 frequency 频率的快照行情触发 onSnapshot |
“matchingMode“ | 订单撮合模式 | 日频:模式一,以收盘价撮合订单模式二,以开盘价撮合订单分钟频率:模式一,行情时间大于订单时间时撮合订单模式二,行情时间等于订单时间时以当前行情的收盘价撮合订单,后续未完成订单撮合订单通模式一 |
“benchmark” | ||
“frequency” | frequency>0 时,行情为逐笔行情,引擎内部合成 frequency 频率的行情触发 onSnapshot | 默认为 0 |
"msgAsTable" | 行情的数据格式 | 行情的数据格式,table 或 dict |
"latency" | 订单延时 | |
“orderBookMatchingRatio” | 与行情订单薄的成交百分比 | |
“matchingRatio” | ||
“enableSubscriptionToTickQuotes” | 是否订阅逐笔行情 | 设置为 true 时,需定义 onTick 回调函数 |
“outputQueuePosition” | 是否需要获取订单在行情中的位置 | 设置为 true 时,当订单还没有完全成交时,可以通过 getOpenOrders 接口实时获取优于委托订单价格的行情未成交委托总量,次于委托订单价格的行情未成交委托总量,等于委托订单价格的行情未成交委托总量,等于委托订单价格的但早于委托的行情未成交委托总量;订单提交时,订单状态明细表也可以获取以上统计指标。 |
“prevClosePrice” | 前收盘价数据表 | 为以下三列的表:[symbol,tradeDate,prevClosePrice]在深交所的逐笔行情时,科创版股票的前收盘价必须设置,否则订单撮合结果可能不符合预期 |
“stockDividend” | 分红除权基本信息表 | [symbol, endDate, annDate, recordDate, exDate, payDate, divListdate, bonusRatio, capitalConversion, afterTaxCashDiv, allotPrice, allotRatio] |
分红除权基本信息表说明如下:
字段 | 名称 |
---|---|
symbol | 股票代码 |
endDate | 分红年度 |
annDate | 预案公告日 |
recordDate | 股权登记日 |
exDate | 除权除息日 |
payDate | 派息日 |
divListDate | 红股上市日 |
bonusRatio | 每股送股比例 |
capitalConversion | 每股转增比例 |
afterTaxCashDiv | 每股分红(税后) |
allotPrice | 配股价格 |
allotRatio | 每股配股比例 |
userConfig=dict(STRING,ANY)
userConfig["startDate"]= 2022.04.13
userConfig["endDate"]= 2022.04.13
///策略类型,暂时固定股票///
userConfig["strategyGroup"]= "stock"
///初始资金
userConfig["cash"]= 100000000
///手续费,
userConfig["commission"]= 0.00015
//印花税,
userConfig["tax"]= 0.001
///以指定的频率通过逐笔数据合成快照。(只有快照行情时,frequency设置无效)
userConfig["frequency"]= 1000
///dataType=0表示逐笔模式撮合,
///dataType=1表示按快照模式一撮合,
///dataType=2按快照模式二撮合
userConfig["dataType"]= 2
//与行情订单薄的成交百分比
userConfig["orderBookMatchingRatio"]=1
///快照模式下,快照的区间成交百分比
userConfig["matchingRatio"]=1
////tick的数据格式,table或dict
userConfig["msgAsTable"]= false
try{Backtest::dropBacktestEngine("backtestMM")}catch(ex){print ex}
engine = Backtest::createBacktestEngine("backtestMM", userConfig,,
initialize, beforeTrading,onTick,onSnapshot,onOrder,onTrade,afterTrading,finalize)
行情数据模块说明
逐笔 + 快照或逐笔合成快照行情
- 行情为逐笔 + 快照或逐笔合成快照,输入表结构为:
colName=`msgTime`msgType`msgBody`symbol`channelNo`seqNum
colType= [TIMESTAMP, SYMBOL, BLOB,STRING,INT,LONG]
messageTable=streamTable(10000000:0, colName, colType)
标的代码 symbol 必须带有交易所标识(".XSHG",".XSHE")结尾,如 600000.XSHG,不然报错。
带有逐笔行情时,msgType 有 "entrust", "trade", "snapshot", "END" 四种,使用逐笔合成指定频率的快照时可以不用”snapshot"行情,其中三个表结构分别如下:
逐笔数据 entrust 和 trade 的表结构如下:
name | type | 备注 |
---|---|---|
symbol | symbol | 股票代码上交所以".XSHG"结尾深交所以"XSHE"结尾 |
symbolSource | STRING | "XSHG"(上交所)或者"XSHE"(深交所) |
timestamp | TIMESTAMP | |
sourceType | INT | 0 代表委托数据 entrust;1 代表成交表 trade |
orderType | INT | entrust:1 市价;2 限价;3 本方最优;10 撤单(仅上交所,即上交所撤单记录在 entrust 中)trade:0 成交;1 撤单(仅深交所,即深交所撤单记录在 trade 中) |
price | DOUBLE | 订单价格 |
qty | LONG | 订单数量 |
buyNo | LONG | trade 对应其原始数据;entrust 中的委托单号填充, |
sellNo | LONG | trade 对应其原始数据;entrust 中的委托单号填充, |
direction | INT | 1(买)or 2(卖) |
channelNo | INT | 通道号 |
seqNum | LONG | 逐笔数据序号 |
逐笔行情时 snapshot 表如下:
name | type | 备注 |
---|---|---|
symbol | symbol | 股票代码上交所以".XSHG"结尾深交所以"XSHE"结尾 |
symbolSource | STRING | "XSHG"(上交所)或者"XSHE"(深交所) |
timestamp | TIMESTAMP | 时间戳 |
lastPrice | DOUBLE | 最新成交价 |
upLimitPrice | DOUBLE | 涨停价 |
downLimitPrice | DOUBLE | 跌停价 |
totalBidQty | LONG | 区间买量 |
totalOfferQty | LONG | 区间卖量 |
bidPrice | DOUBLE[] | 委买价格列表 |
bidQty | LONG[] | 委买量列表 |
offerPrice | DOUBLE[] | 委卖价格列表 |
offerQty | LONG[] | 委卖量列表 |
signal | DOUBLE[] | 指标列表 |
seqNum | LONG | 逐笔数据序号 |
prevClosePrice | DOUBLE | 前收盘价 |
msgType 为”END“时策略回测结束。可以在行情回放结束之后,增加一条 msgType 为”END“的消息。如下示例:
messageTable=select top 1* from messageTable where msgTime=max(msgTime)
update messageTable set msgType="END"
update messageTable set msgTime=concatDateTime(msgTime.date(),16:00:00)
Backtest::appendQuotationMsg(engine,messageTable)
快照或快照 + 成交行情
为快照行情时:
colName=["symbol","symbolSource","timestamp","lastPrice","upLimitPrice", "downLimitPrice","totalBidQty","totalOfferQty","bidPrice","bidQty", "offerPrice","offerQty","signal","prevClosePrice"] colType= ["STRING","STRING","TIMESTAMP","DOUBLE","DOUBLE","DOUBLE","LONG", "LONG","DOUBLE[]","LONG[]","DOUBLE[]","LONG[]","DOUBLE[]","DOUBLE"] messageTable=table(10000000:0, colName, colType)
为快照 + 成交行情时:
colName=["symbol","symbolSource","timestamp","lastPrice","upLimitPrice", "downLimitPrice","totalBidQty","totalOfferQty","bidPrice","bidQty", "offerPrice","offerQty","tradePrice","tradeQty","signal","prevClosePrice"] colType= ["STRING","STRING","TIMESTAMP","DOUBLE","DOUBLE","DOUBLE","LONG", "LONG","DOUBLE[]","LONG[]","DOUBLE[]","LONG[]","DOUBLE[]","LONG[]","DOUBLE[]","DOUBLE"] messageTable=table(10000000:0, colName, colType)
标的代码 symbol 必须带有交易所标识(".XSHG",".XSHE")结尾,如 600000.XSHG,不然报错。
快照 (dataType=1) 或快照 + 成交 (dataType=2) 行情数据字段如下(dataType=1 时,没有 tradePrice 和 tradeQty 两个字段)
name type 备注 symbol symbol 股票代码上交所以".XSHG"结尾深交所以"XSHE"结尾 symbolSource STRING "XSHG"(上交所)或者"XSHE"(深交所) timestamp TIMESTAMP lastPrice DOUBLE 最新成交价 upLimitPrice DOUBLE downLimitPrice DOUBLE totalBidQty LONG totalOfferQty LONG bidPrice DOUBLE[] bidQty LONG[] offerPrice DOUBLE[] offerQty LONG[] tradePrice DOUBLE[] dataType = 2 时才有 tradeQty LONG[] dataType = 2 时才有 signal DOUBLE[] 指标列表 prevClosePrice DOUBLE 引擎接收到 symbol 为”END”时,表示策略回测结束
一般在回测行情回放结束之后,再发送一条 symbol 为”END”的消息,如下示例:
messageTable=select top 1* from messageTable where timestamp=max(timestamp) update messageTable set symbol="END" //update messageTable set msgTime=concatDateTime(timestamp.date(),16:00:00) Backtest::appendQuotationMsg(engine,messageTable)
分钟频率或日频
为分钟频率或日频:
colName=`symbol`tradeTime`open`low`high`close`volume`amount`upLimitPrice`downLimitPrice`prevClosePrice`signal
colType=[SYMBOL,TIMESTAMP,DOUBLE,DOUBLE,DOUBLE,DOUBLE,LONG,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE[]]
messageTable=table(10000000:0, colName, colType)
- 标的代码 symbol 必须带有交易所标识(".XSHG",".XSHE")结尾,如 600000.XSHG,不然报错。
- 引擎接收到 symbol 为”END”时,表示策略回测结束
- 涨停价 upLimitPrice 不为 0 时,委托买单价格大于等于涨停价会被拒单
- 跌停价 downLimitPrice 不为 0 时,委托卖单价格小于等于跌停价会被拒单
一般在回测行情回放结束之后,可以再发生一条 symbol 为”END”的消息,如下示例:
messageTable=select top 1* from messageTable where tradeTime=max(tradeTime)
update messageTable set symbol="END"
update messageTable set tradeTime=concatDateTime(tradeTime.date(),16:00:00)
Backtest::appendQuotationMsg(engine,messageTable)
策略编写模块
使用回测引擎进行策略回测时采取的是事件驱动机制,策略回测架构提供以下多个事件函数。
事件函数 | 说明 |
---|---|
def initialize(mutable contextDict){} | 策略初始化函数,只触发一次。可以在该函数中初始化一些变量,或者订阅指标计算。回调函数传入参数 contextDict 为逻辑上下文,是由回测引擎创建的字典变量 |
def beforeTrading(mutable contextDict){} | 策略盘前交易函数,每日盘前触发一次。可以在该函数中一些启动前的准备,如订阅行情等 |
def onTick(mutable contextDict, msg){} | 逐笔行情通知函数,行情更新时的处理函数,逐笔委托和成交。 |
def onSnapshot(mutable contextDict, msg){} | 快照行情通知函数 |
def onOrder(mutable contextDict,orders){} | 委托回报通知函数,每个订单状态有变化时会触发。 |
def onTrade(mutable contextDict,trades){} | 成交回报通知函数,有成交时会触发。 |
def afterTrading(mutable contextDict){} | 策略每日盘后回调函数,每日盘后触发一次。可以在该函数统计当日的成交等信息 |
def finalize(mutable contextDict){} | 策略结束之后回调函数 |
逐笔行情回调函数 onTick
contextDict 为上下文
msg 为 tick 数据,为表或者字典。
字典是,包含 symbol 为 key 值的 tick 数据字典,每个 tick 对象包含字段如下:
name | type | 备注 |
---|---|---|
symbol | symbol | 股票代码 |
symbolSource | STRING | |
timestamp | TIMESTAMP | |
sourceType | INT | 0 代表委托数据 entrust;1 代表成交表 trade |
orderType | INT | entrust:1 市价;2 限价;3 本方最优;10 撤单(仅上交所,即上交所撤单记录在 entrust 中)trade:0 成交;1 撤单(仅深交所,即深交所撤单记录在 trade 中) |
price | DOUBLE | 订单价格 |
qty | LONG | 订单数量 |
buyNo | LONG | |
sellNo | LONG | |
direction | INT | 1(买)or 2(卖) |
channelNo | INT | 通道号 |
seqNum | LONG | 逐笔数据序号 |
快照行情回调函数 onSnapshot
contextDict 为上下文
msg 为 snapShot 数据,为表或者字典。
字典是,包含 symbol 为 key 值的 snapShot 数据字典,每个 snapShot 对象包含字段如下:
名称 | 类型 | 含义 |
---|---|---|
symbol | SYMBOL | 股票标的 |
symbolSource | SYMBOL | 证券市场:深交所、上交所 |
timestamp | TIMESTAMP | 时间 |
lastPrice | DOUBLE | 最新成交价 |
upLimitPrice | DOUBLE | 涨停板价 |
downLimitPrice | DOUBLE | 跌停板价 |
totalBidQty | LONG | 买单成交数量总和 |
totalOfferQty | LONG | 卖单成交数量总和 |
bidPrice | DOUBLE[] | 买单价格列表 |
bidQty | LONG[] | 买单数量列表 |
offerPrice | DOUBLE[] | 卖单价格列表 |
offerQty | LONG[] | 卖单数量列表 |
signal | DOUBLE[] |
K 线行情回调函数 onBar
contextDict 为上下文
msg 为 K 线数据,为表或者字典。
字典是,包含 symbol 为 key 值的日频或者分钟频率的 K 线数据字典,每个 K 线包含字段如下
字段 | 类型 | 名称 | 备注 |
---|---|---|---|
symbol | SYMBOL | 标的代码 | “.XSHE”或者“.XSHG”结尾标识 |
tradeTime | TIMESTAMP | 交易日 | |
open | DOUBLE | 开盘价 | |
low | DOUBLE | 最低价 | |
high | DOUBLE | 最高价 | |
close | DOUBLE | 收盘价 | |
volume | LONG | 成交量 | |
amount | DOUBLE | 成交额 | |
upLimitPrice | DOUBLE | 涨停价 | |
downLimitPrice | DOUBLE | 跌停价 | |
prevClosePrice | DOUBLE | 前收盘价 | |
signal | DOUBLE[] | 其它 |
委托回报 onOrder
contextDict 为上下文
orders 为订单信息的字典列表:
名称 | 含义 | 类型 | |
---|---|---|---|
orderId | 委托订单 id | int → long | |
symbol | 标的代码 | ||
timestamp | 委托时间 | ||
qty | 委托数量 | ||
price | 委托价格 | ||
status | 委托状态 | 4:已报 0:部成 1:已成 2:撤单成功 -1:审批拒绝 -2:撤单拒绝 | |
direction | 委托方向 | ||
tradeQty | 成交数量 | ||
tradeValue | 成交金额 | ||
label | |||
updateTime |
成交回报函数 onTrade
contextDict 为上下文
trades 为订单信息的字典列表:
字段 | 名称 | 备注 |
---|---|---|
orderId | 委托订单 id | |
symbol | 标的代码 | |
tradePrice | 成交价格 | |
tradeQty | 成交数量 | int |
tradeValue | 成交金额 | |
totalFee | ||
totalVolume | 累计成交量 | |
totalValue | 累计成交金额 | |
direction | 委托方向 | |
tradeTime | 成交时间 | |
orderPrice | 委托价格 | |
label |
示例
def initialize(mutable contextDict){
//订阅指标
print("initialize")
d=dict(STRING,ANY)
d["zdf"]=<zdf(lastPrice,prevClosePrice)>
d["totalSellAmount"]=<totalSellAmount(offerQty)>
Backtest::subscribeIndicator(contextDict["engine"], "snapshot", d)
//订阅逐笔行情的指标
d=dict(STRING,ANY)
d["zdf_30s"]=<zdf_30s(price,time,sourceType,orderType)>
d["tradeVol_5m"]=< tradeVol_5m(qty,time,sourceType,orderType)>
//d["sourceType"]=<sourceType>
Backtest::subscribeIndicator(contextDict["engine"], "tick", d)
}
def beforeTrading(mutable contextDict){
//每日盘前回调函数
//1、通过contextDict["tradeDate"]可以获取当日;
print("before_trading")
}
def onTick(mutable contextDict, msg){
////msg可以为字典或表,最新时刻的tick数据
///1、通过contextDict["tradeTime"]获取最新时间
for (istock in msg.keys()){
askPrice=msg[istock]["offerPrice"][0]
bidPrice=msg[istock]["bidPrice"][0]
if(any([askPrice,bidPrice]<=0) or any(isNull([askPrice,bidPrice]))){
continue
}
buyQty=100
sellQty=100
buyOrderId=Backtest::submitOrder(contextDict["engine"],
(istock, contextDict["tradeTime"], 5, bidPrice, buyQty, 1, 1))[0]
}
}
def onOrder( mutable contextDict,orders){
/*
orderId->474
symbol->688157.XSHG
timestamp->2022.04.11T09:50:43.000
amount->1100
price->94.319999999999993
status->9
direction->2
tradeQty->1100
tradeValue->0
label->"a"
updateTime->2022.04.11T09:50:43.000
*/
}
def onTrade(mutable contextDict,trades){
/*
* trades为字典列表
orderId->376
symbol->688157.XSHG
tradePrice->93.959999999999993
tradeQty->200
tradeTime->2022.04.11T09:53:16.220
direction->2
tradeValue->18792//成交金额
label->
*/
///成交主推回调
for(itrade in trades){}
}
def afterTrading(mutable contextDict){
print ("after_trading")
//print
//每日盘后回调函数
}
def finalize(mutable contextDict){
//回测结束前回调函数
}
引擎接口
createBacktestEngine 创建回测引擎,设置所有的回调函数
Backtest::createBacktestEngine(name, userConfig,basicInfo,
initialize, beforeTrading,onTick,onSnapshot,onOrder,onTrade,afterTrading,finalize)
入参 | 名称 | 类型 | 是否是必填项 | 备注 |
---|---|---|---|---|
name | 回测引擎名称 | string | 是 | |
userConfig | 回测引擎的设置 | dict | 是 | |
basicInfo | 否 | |||
initialize | 初始化回调函数 | 是 | ||
beforeTrading | 是 | |||
onTick/onBar | 逐笔行情回调函数 | 否 | 订阅逐笔行情的时候触发 | |
onSnapshot | 快照行情回调函数 | 是 | ||
onOrder | 是 | |||
onTrade | 是 | |||
afterTrading | 是 | |||
finalize | 是 |
appendQuotationMsg 插入行情执行策略回测
Backtest::appendQuotationMsg(engine,msg)
入参 | 名称 | 是否是必填项 |
---|---|---|
engine | 回测引擎 | 是 |
msg | 行情 | 是 |
subscribeIndicator 订阅指标
d=dict(STRING,ANY)
d["mavg"]=<mavg(lastPrice,20)>
Backtest::subscribeIndicator(contextDict["engine"], "snapshot", d)
Backtest::subscribeIndicator(contextDict["engine"], "tick", d)
d=dict(STRING,ANY)
d["mavg"]=<mavg(trade,20)>
Backtest::subscribeIndicator(contextDict["engine"], "trade", d)
d=dict(STRING,ANY)
d["mavg"]=<mavg(clsoe,20)>
Backtest::subscribeIndicator(contextDict["engine"], "kline", d)
订阅行情指标时,内部创建了相应的响应式状态引擎,状态因子的编写参考:DolphinDB 响应式状态引擎介绍教程。
submitOrder 下单接口
Backtest::submitOrder(engine, msg,label="")
入参 | 名称 | 类型 | 是否是必填项 | 备注 |
---|---|---|---|---|
engine | 回测引擎名称 | 是 | 在回测框架里通过 contextDict["engine"]模式调用当前的引擎名称 | |
msg | 订单信息 | 元组或表 | 是 | (股票代码,下单时间,订单类型,订单价格,订单数量,买卖方向) 买卖方向:1:买开;2 卖开;3:卖平;4:买平订单类型:上交所:0:市价单中最优五档即时成交剩余撤销委托订单 1:市价单中最优五档即时成交剩余转限价委托订单 2:市价单中本方最优价格委托订单 3:市价单中对手方最优价格委托订单 5:限价单 6:撤单深交所:0:市价单中最优五档即时成交剩余撤销委托订单 1:市价单中即时成交剩余撤销委托订单 2:市价单中本方最优价格委托订单 3: 市价单中对手方最优价格委托订单 4:市价单中全额成交或撤销委托订单 5:限价单 6:撤单 |
label | 备注 | string | 否 | 这个用户可以设置,用于对订单进行分类 |
setUniverse 设置股票池
Backtest::setUniverse(engine,symbolList)
其中 symbolList 是一个 string vector,内含股票代码
cancelOrder 取消订单接口
Backtest::cancelOrder(engine,symbol=NULL,orders=NULL,label="")
入参 | 名称 | 类型 | 是否是必填项 | 备注 |
---|---|---|---|---|
engine | 引擎 | |||
symbol | 证券代码 | Symbol | 否 | 只支持单个 |
orders | 订单列表 | [] | 否 | orders 不为空时,取消指定订单 |
label |
getOpenOrders 获取未成交订单
查询未成交订单
Backtest::getOpenOrders(engine,symbol=NULL,orders=NULL,label="",outputQueuePosition=false)
入参 | 名称 | 类型 | 是否是必填项 | 备注 |
---|---|---|---|---|
engine | 引擎名称 | 是 | ||
symbol | 证券代码 | Symbol | 否(返回所有的未成交订单) | 只支持单个 |
orders | 订单列表 | list | 否 | orders 不为空时,查询指定订单 |
label | string | |||
outputQueuePosition | BOOL |
返回如下:
返回值是一个表。包含如下列:
注意:仅当 outputQueuePosition=1 和 2 时,包含 openVolumeWithBetterPrice, openVolumeWithWorsePrice, openVolumeAtOrderPrice, priorOpenVolumeAtOrderPrice, depthWithBetterPrice 五列。
名称 | 类型 | 含义 |
---|---|---|
orderId | LONG | 订单 ID |
timestamp | TIMESTAMP | 时间 |
symbol | STRING | 股票标的 |
price | DOUBLE | 委托价格 |
totalQty | LONG | 用户订单数量 |
openQty | LONG | 用户订单余量 |
direction | INT | 1(买),2(卖) |
isMacthing | INT | 订单是否到达撮合时间 |
openVolumeWithBetterPrice | LONG | 优于委托价格的行情未成交委托单总量 |
openVolumeWithWorsePrice | LONG | 次于委托价格的行情未成交委托单总量 |
openVolumeAtOrderPrice | LONG | 等于委托价格行情未成交委托单总量 |
priorOpenVolumeAtOrderPrice | LONG | 等于委托价格行情且比自己早的行情未成交委托单总量 |
depthVolumeWithBetterPrice | INT | 优于委托价格的行情未成交价格档位深度 |
updateTime | TIMESTAMP | 最新更新时间 |
dropBacktestEngine 删除回测引擎
Backtest::dropBacktestEngine(engine)
getPosition 获取持仓
Backtest::getPosition(engine,symbol="")
入参 | 名称 | 类型 | 是否是必填项 | 备注 |
---|---|---|---|---|
engine | 回测引擎名称 | long | 是 | 在回测框架里通过 contextDict["engine"]模式调用当前的引擎名称 |
symbol | 股票代码 | string | 否 | "688157.XSHG" |
返回表如下:
字段 | 名称 | ||||||
---|---|---|---|---|---|---|---|
symbol | 标的代码 | ||||||
lastDayLongPosition | 昨买持仓数量 | 昨日收盘时的买开的持仓量 | 买开,买卖标志为 1 | ||||
lastDayShortPosition | 昨卖持仓数量 | 昨日收盘时的卖开的持仓量 | 卖开,买卖标志为 2 | ||||
longPosition | 买持仓量 | sum(买开成交数量 - 卖平成交数量) | 买卖标志为 1 的成交数量 - 买卖标志为 3 的成交数量 | ||||
longPositionAvgPrice | 买成交均价 | sum(买开成交数量*买开成交价格)\sum(买开成交数量) | 买开时计算 | ||||
shortPosition | 卖持仓量 | sum(卖开成交数量 - 买平成交量) | 卖开,买卖标志为 2 | ||||
shortPositionAvgPrice | 卖成交均价 | sum(卖开成交数量*卖开成交价格)\sum(卖成交数量) | 卖开时计算 | ||||
todayBuyVolume | 当日买成交数量 | sum(当日买开成交数量) | |||||
todayBuyValue | 当日买成交金额 | sum(当日买开成交数量*当日买开成交价格) | |||||
todaySellVolume | 当日卖成交数量 | sum(当日卖开成交数量) | |||||
todaySellValue | 当日卖成交金额 | sum(当日卖开成交数量*当日卖开成交价格) |
getTradeDetails 获取交易明细表
Backtest::getTradeDetails(long(engine))
返回明细表
字段 | 含义 |
---|---|
orderId | 订单号 |
symbol | |
direction | 订单委托买卖标志 |
sendTime | 订单委托时间 |
orderPrice | 订单委托价格 |
orderQty | 订单委托数量 |
tradeTime | 订单成交时间 |
tradePrice | 成交价格 |
tradeQty | 成交数量 |
orderStatus | orderStatus 表示订单状态,4:已报 0:部成 1:已成 2:撤单成功 -1:审批拒绝 -2:撤单拒绝 -3:未成交的订单 |
label |
getAvailableCash 查询账户可用现金
Backtest::getAvailableCash(long(engine))
///100135665.66910028
getTodayPnl 查询当日股票盈亏情况
Backtest::getTodayPnl(long(engine),"688157.XSHG")
输出表
字段 | 名称 |
---|---|
symbol | 标的代码 |
pnl | 当日账户盈亏金额(包含昨仓) |
todayPnl | 当日盈亏金额(不包含昨仓) |
getDailyPosition 获取每日持仓数据详情
一般回测结束调用,返回每日盘后的持仓数据表
Backtest::getDailyPosition(engine) //
股票每日持仓返回统计字段:
字段 | 名称 |
---|---|
symbol | 标的代码 |
tradeDate | 交易日 |
lastDayLongPosition | 昨日买持仓 |
lastDayShortPosition | 昨日卖持仓 |
longPosition | 买持仓 |
longPositionAvgPrice | 买成交均价 |
shortPosition | 卖成交数量 |
shortPositionAvgPrice | 卖成交均价 |
todayBuyVolume | 当日买成交数量 |
todayBuyValue | 当日买成交金额 |
todaySellVolume | 当日卖成交数量 |
todaySellValue | 当日卖成交金额 |
getDailyTotalPortfolios 获取策略每日权益指标
Backtest::getTotalPortfolios 接口实时获取账户盈亏。
可以在回测结束时调用,每日结束时计算该账户的权益指标:
Backtest::getDailyTotalPortfolios(engine)
字段 | 字段说明 | |
---|---|---|
engine | 引擎 |
计算字段:
InitialCash−账户的初始现金
字段名称 | 字段说明 |
---|---|
tradeDate | 日期 |
cash | 可用资金 |
totalMarketValue | 账户总市值 |
totalEquity | 账户总权益 |
netValue | 账户单位净值 |
totalReturn | 截至当日的累计收益率 |
ratio | 账户每日收益率 |
pnl | 账户当日盈亏 |
getReturnSummary 获取策略的收益概述
回测结束时计算该模块
Backtest::getReturnSummary(engine)
字段 | 字段说明 | |
---|---|---|
engine | 引擎 |
输出字段:
计算公式中的
value:为每日净值 netValue
price:基准每日净值数据(设置 benchmark 时)
字段名称 | 字段说明 | 计算公式 |
---|---|---|
totalReturn | 总收益 | last(value)-1 |
annualReturn | 年化收益率 | pow(last(value), 252\size(value)) - 1 |
annualVolatility | 年化波动率 | std(deltas(value)\prev(value)) * sqrt(252) |
annualSkew | 收益率偏度 | skew(deltas(value)\prev(value)) |
annualKur | 收益率峰度 | kurtosis(deltas(value)\prev(value)) |
sharpeRatio | 夏普率 | (getAnnualReturn(value) - r)\getAnnualVolatility(value) |
maxDrawdown | 最大回撤 | i = imax((cummax(value) - value) \ cummax(value)) if (i==0){ return 0 } j = imax(value[:i])(value[j] - value[i]) \ (value[j]) |
drawdownRatio | 收益回撤比 | getAnnualReturn(value) \ getMaxDrawdown(value) |
beta | beta 系数 | covar(deltas(value)\prev(value), deltas(price)\prev(price)) \ std(deltas(price)\prev(price)) |
alpha | a 系数 | annualReturn(value) - beta(value, price) * (annualReturn(price) ) |
turnoverRate | 换手率 | 每日换手率 len(set(当日持股股票集合)-set(前一交易日股票集合))/len(set(前一交易日股票集合));avg(abs(每日换手率)) |
dailyWinningRate | 日胜率 | 当日盈亏大于 0 的次数/总的交易日 |
getBacktestEngineList 获取所有的回测引擎
Backtest::getBacktestEngineList()
getContextDict 回测结束,返回逻辑上下文
Backtest::getContextDict(long(engine))
使用示例
编写好策略之后,进行策略配置以及创建回测引擎并执行策略回测
userConfig=dict(STRING,ANY)
userConfig["startDate"]= 2022.04.13
userConfig["endDate"]= 2022.04.13
///策略类型,暂时固定股票///
userConfig["strategyGroup"]= "stock"
///初始资金
userConfig["cash"]= 100000000
///手续费,
userConfig["commission"]= 0.00015
//印花税,
userConfig["tax"]= 0.001
userConfig["latency"]= 10
///以指定的频率通过逐笔数据合成快照。(只有快照行情时,frequency设置无效)
userConfig["frequency"]= 1000
///dataType=0表示,逐笔模式撮合,
///dataType=1表示按快照模式一撮合,
///dataType=2按快照模式二撮合
userConfig["dataType"]= 2
//与行情订单薄的成交百分比,(逐笔撮合时,orderBookMatchingRatio参数无效)
userConfig["orderBookMatchingRatio"]=1
///快照模式下,快照的区间成交百分比,(逐笔撮合时,matchingRatio参数无效)
userConfig["matchingRatio"]=1
////tick的数据格式,table或dict
userConfig["msgAsTable"]= false
name="test01"
try{Backtest::dropBacktestEngine(strategyName)}catch(ex){print ex}
engine = Backtest::createBacktestEngine(name, userConfig,,
initialize, beforeTrading,onTick,onSnapshot,onOrder,onTrade,afterTrading,finalize)