Backtest
通过 DolphinDB 的 Backtest 插件,用户可以输入历史行情数据并应用自己的交易策略,来帮助制定和优化交易策略。
安装插件
版本要求
DolphinDB Server 2.00.12 及更高版本,支持 X86-64 的 Linux 和 Windows。
安装步骤
在 DolphinDB 客户端中使用
listRemotePlugins
命令查看插件仓库中的插件信息。注意:仅展示当前操作系统和 server 版本支持的插件。若无预期插件,可自行编译(请自行选择对应分支下的插件)或在 DolphinDB 用户社区进行反馈。
login("admin", "123456") listRemotePlugins()
使用
installPlugin
命令完成插件安装。installPlugin("Backtest")
使用
loadPlugin
命令加载插件。loadPlugin("Backtest")
插件依赖
回测引擎插件内部依赖模拟撮合引擎插件,因此加载回测引擎之前需要先加载模拟撮合引擎,该插件同样可以通过插件市场安装。
使用
installPlugin
命令完成模拟撮合引擎插件安装。installPlugin("MatchingEngineSimulator")
使用
loadPlugin
命令加载模拟撮合引擎插件。loadPlugin("MatchingEngineSimulator")
用户配置模块说明
用户可以配置回测的开始和结束日期,初始资金,手续费和印花税,订单的撮合模式。
key | 说明 | 说明 |
---|---|---|
startDate | 开始日期 | |
endDate | 结束日期 | |
strategyGroup | 策略类型 | 暂时固定股票:stock |
cash | 初始资金量 | |
commission | 手续费 | |
tax | 印花税 | |
dataType | 行情类型(0: 逐笔快照, 1: 快照, 2: 快照+历史, 3: 分钟频率, 4: 日频) | frequency > 0 且 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 | 前收盘价数据表 | 为以下三列的表: 在深交所的逐笔行情时,科创版股票的前收盘价必须设置,否则订单撮合结果可能不符合预期 |
stockDividend | 分红除权基本信息表 |
红除权基本信息表说明如下:
字段 | 名称 |
---|---|
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{dropBacktestEngine("BacktestMM")}catch(ex){print ex}
engine = 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)
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)
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)
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 对象包含字段如下:
name | type | 备注 |
---|---|---|
symbol | SYMBOL | 股票标的 |
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 |
K线行情回调函数onBar
contextDict 为上下文,msg 为K线数据,为表或者字典。
字典是,包含 symbol 为key 值的日频或者分钟频率的 K 线数据字典,每个 K 线包含字段如下:
name | type | 备注 |
---|---|---|
symbol | SYMBOL | 股票标的 |
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 | 成交数量 |
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)>
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>
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=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
语法
createBacktestEngine(name, userConfig, basicInfo, initialize, beforeTrading, onTick, onSnapshot, onOrder, onTrade, afterTrading, finalize)
详情 创建回测引擎,并设置所有的回调函数。
返回创建的回测引擎句柄。
参数
name STRING 类型标量,表示回测引擎名称。
userConfig 一个字典,键是 STRING 类型,代表配置项的名称,值是配置项对应的值。
basicInfo 基础信息表,可选参数。
initialize 初始化回测函数,回测开始时会触发调用。
beforeTrading 策略回调函数,每日开盘前触发调用。
onTick/onBar 策略回调函数,不同模式下填写的函数不同,可选参数。处理逐高频行情时会触发调用 onTick,中低频行情时触发调用onBar。
onSnapshot 策略回调函数,处理快照行情时会触发调用。
onOrder 策略回调函数,订单变更时触发调用。
onTrade 策略回调函数,订单交易时触发调用。
afterTrading 策略回调函数,每日收盘时触发调用。
finalize 策略回调函数,回测结束时会触发调用。
appendQuotationMsg
语法
appendQuotationMsg(engine, msg)
详情 插入行情执行策略回测。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
msg 行情输入表。
subscribeIndicator
语法
subscribeIndicator(engine, type, metrics)
详情 订阅指标。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
type STRING 类型标量,表示要订阅指标的行情类型,支持 "tick", "snapshot" 和 "kline"。
metrics 一个字典,键是 STRING 类型,代表指标名,值是以元代码的形式表示计算公式,代表如何计算指标。
示例
d=dict(STRING,ANY)
d["mavg"]=<mavg(lastPrice,20)>
subscribeIndicator(contextDict["engine"], "snapshot", d)
subscribeIndicator(contextDict["engine"], "tick", d)
d=dict(STRING,ANY)
d["mavg"]=<mavg(trade,20)>
subscribeIndicator(contextDict["engine"], "trade", d)
d=dict(STRING,ANY)
d["mavg"]=<mavg(clsoe,20)>
subscribeIndicator(contextDict["engine"], "kline", d)
订阅行情指标时,内部创建了相应的响应式状态引擎,状态因子的编写参考 DolphinDB 响应式状态引擎介绍教程。
submitOrder
语法
submitOrder(engine, msg, label="")
详情 向回测引擎发送订单。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
msg 订单内容,一个元组,表示订单内容,其格式为(股票代码, 下单时间, 订单类型, 订单价格, 订单数量, 买卖方向)。
- 订单类型:
- 上交所:0:市价单中最优五档即时成交剩余撤销委托订单;1:市价单中最优五档即时成交剩余转限价委托订单;2:市价单中本方最优价格委托订单;3:市价单中对手方最优价格委托订单;5:限价单;6:撤单。
- 深交所:0:市价单中最优五档即时成交剩余撤销委托订单;1:市价单中即时成交剩余撤销委托订单;2:市价单中本方最优价格委托订单;3: 市价单中对手方最优价格委托订单;4:市价单中全额成交或撤销委托订单;5:限价单;6:撤单。
- 买卖方向:INT 类型正数,1 代表买开,2 代表卖开,3 代表卖平,4 代表买平。
label STRING 类型标量,对该订单增加备注信息。
setUniverse
语法
setUniverse(engine, symbolList)
详情 设置股票池。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
symbolList STRING 类型向量,内含证券代码。
cancelOrder
语法
cancelOrder(engine, symbol="", orders=NULL, label="")
详情 取消订单。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
symbol SYMBOL 类型标量,要取消的订单的证券代码,可选参数。
orders DOUBLE 类型向量,要取消的订单 ID 列表,可选参数。
label STRING 类型标量,要取消的订单的备注信息。
getOpenOrders
语法
getOpenOrders(engine, symbol="", orders=NULL, label="", outputQueuePosition=false)
详情 查询未成交订单。
返回未成交订单表,包含如下列:
注意:仅当 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 | 最新更新时间 |
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
symbol SYMBOL 类型标量,证券代码,可选参数。
orders DOUBLE 类型向量,订单 ID 列表,可选参数。
label STRING 类型标量,用作备注,可选参数。
outputQueuePosition BOOL 类型标量,是否输出额外信息,可选参数。
dropBacktestEngine
语法
dropBacktestEngine(engine)
详情 删除回测引擎。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
getPosition
语法
getPosition(engine, symbol="")
详情 获取持仓信息表。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
symbol SYMBOL 类型标量,证券代码,可选参数。
返回值 返回持仓信息表
字段 | 名称 | ||
---|---|---|---|
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
语法
getTradeDetails(engine)
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
详情 获取交易明细表,并返回:
字段 | 含义 |
---|---|
orderId | 订单号 |
symbol | 证券代码 |
direction | 订单委托买卖标志 |
sendTime | 订单委托时间 |
orderPrice | 订单委托价格 |
orderQty | 订单委托数量 |
tradeTime | 订单成交时间 |
tradePrice | 成交价格 |
tradeQty | 成交数量 |
orderStatus | orderStatus表示订单状态。4:已报,0:部成,1:已成,2:撤单成功,-1:审批拒绝,-2:撤单拒绝,-3:未成交的订单 |
label | 备注 |
getAvailableCash
语法
getAvailableCash(engine)
详情 查询账户可用现金。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
getTodayPnl
语法
getTodayPnl(engine, symbol)
详情 查询当日股票盈亏情况,并返回:
字段 | 含义 |
---|---|
symbol | 证券代码 |
pnl | 当日账户盈亏金额(包含昨仓) |
todayPnl | 当日盈亏金额(不包含昨仓) |
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
symbol SYMBOL 类型标量,表示证券代码。
getDailyPosition
语法
getDailyPosition(engine)
详情 获取每日盘后的持仓数据详情,并返回:
字段 | 名称 |
---|---|
symbol | 标的代码 |
tradeDate | 交易日 |
lastDayLongPosition | 昨日买持仓 |
lastDayShortPosition | 昨日卖持仓 |
longPosition | 买持仓 |
longPositionAvgPrice | 买成交均价 |
shortPosition | 卖成交数量 |
shortPositionAvgPrice | 卖成交均价 |
todayBuyVolume | 当日买成交数量 |
todayBuyValue | 当日买成交金额 |
todaySellVolume | 当日卖成交数量 |
todaySellValue | 当日卖成交金额 |
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
getDailyTotalPortfolios
语法
getDailyTotalPortfolios(engine)
详情 获取策略每日权益指标,并返回每日权益表:
字段名称 | 字段说明 |
---|---|
tradeDate | 日期 |
cash | 可用资金 |
totalMarketValue | 账户总市值 |
totalEquity | 账户总权益 |
netValue | 账户单位净值 |
totalReturn | 截至当日的累计收益率 |
ratio | 账户每日收益率 |
pnl | 账户当日盈亏 |
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
getReturnSummary
语法
getReturnSummary(engine)
详情 回测结束时计算策略的收益概述,返回一张收益概述表。
下表中计算公式列里的 value 为每日净值,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);(value - value) \ (value) |
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(每日换手率) |
dailyWinningRate | 日胜率 | 当日盈亏大于0的次数/总的交易日 |
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
getBacktestEngineList
语法
getBacktestEngineList()
详情 获取所有的回测引擎。
getContextDict
语法 getContextDict(engine)
详情 返回逻辑上下文。
参数
engine 通过 createBacktestEngine
接口创建的回测引擎句柄。
示例
编写好策略之后,进行策略配置以及创建回测引擎并执行策略回测
listRemotePlugins()
installPlugin("Backtest")
loadPlugin("Backtest")
installPlugin("MatchingEngineSimulator")
loadPlugin("MatchingEngineSimulator")
def initialize(mutable contextDict,userParam){
//通过setUniverse可以更换当日股票池,
//如setUniverse(contextDict["engine"],["688088.XSHG","688157.XSHG","688208.XSHG"])
print("initialize")
// 网格策略参数
// 初始价格
contextDict["initPrice"] = dict(SYMBOL,ANY)
// 网格间距(百分数)
contextDict["alpha"]=userParam["alpha"]
// 回落间距(百分数)
contextDict["beta"] =userParam["beta"]
// 每格交易金额
contextDict["M"] = userParam["M"]
contextDict["baseBuyPrice"] = dict(SYMBOL,ANY)
contextDict["baseSellPrice"] = dict(SYMBOL,ANY)
contextDict["lowPrice"]=dict(SYMBOL,ANY)
contextDict["highPrice"]=dict(SYMBOL,ANY)
contextDict["N"]=dict(SYMBOL,ANY)
// 手续费费率
contextDict["feeRatio"] = 0.00015
//订阅指标
d=dict(STRING,ANY)
d["mavg"]=<mavg(close,20)>
subscribeIndicator(contextDict["engine"], "kline", d)
//记录每日统计量
contextDict['dailyReport' ]= table(1000:0,[`SecurityID,`tradeDate,`closePrice,`buyVolume,
`buyAmount,`sellVolume,`sellAmount,`PosExposureVolume,`PosExposureValue,`dailyEarning],
[SYMBOL,DATE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE,DOUBLE])
//日志
contextDict["log"]=table(10000:0,[`tradeDate,`time,`info],[DATE,TIMESTAMP,STRING])
}
def beforeTrading(mutable contextDict){
//每日盘前回调函数
//1、通过contextDict["tradeDate"]可以获取当日;
//2、通过setUniverse可以更换当日股票池,
// 如setUniverse(contextDict["engine"],["688088.XSHG","688157.XSHG"])
print ("beforeTrading: "+contextDict["tradeDate"])
tb=contextDict["log"]
contextDict["log"]=tb.append!(table(contextDict["tradeDate"] as tradeDate,now() as time,"beforeTrading" as info))
}
def onBar(mutable contextDict, msg){
////msg可以为字典或表,最新时刻的tick数据
///contextDict["tradeDate"]///当前交易日,需回测框架提供
///contextDict["tradeTime"] ///当前的最新时间,需回测框架提供
// 交易时间
/*
600082->symbol->600082
tradeTime->2023.02.01T12:59:00.000
open->3.5
low->3.5
high->3.5
close->3.5
volume->0
amount->0
upLimitPrice->0
downLimitPrice->0
prevClose->3.5
signal->[3.5]
*/
if(second(contextDict["tradeTime"])<09:30:00 or second(contextDict["tradeTime"])>14:57:00){
return
}
}
def onOrder(mutable contextDict,orders){
}
def onTrade(mutable contextDict,trades){
}
def afterTrading(mutable contextDict){
/*
* 每日盘后调用
*/
tradeDate=contextDict["tradeDate"]
print ("afterTrading: "+tradeDate)
}
def finalized (mutable contextDict){
//print "finalized"
tb=contextDict["log"]
contextDict["log"]=tb.append!(table(contextDict["tradeDate"] as tradeDate,now() as time,"finalized" as info))
print("finalized")
}
// step 1:策略编写
// step 2:策略配置与引擎创建
startDate=2023.02.01
endDate=2023.02.10
userConfig=dict(STRING,ANY)
userConfig["startDate"]=startDate
userConfig["endDate"]=endDate
///策略类型,暂时固定股票///
userConfig["strategyGroup"]= "stock"
///以指定的频率通过逐笔数据合成快照
userConfig["frequency"]= 0
userConfig["cash"]= 100000000
///手续费,
userConfig["commission"]= 0.0
//印花税,
userConfig["tax"]= 0.0
//行情分钟
userConfig["dataType"]= 3
//订单撮合模式
//默认一:行情时间大于订单时间时,进行订单撮合
//默认二:行情时间等于订单时间时,以当前收盘价进行订单撮合,未完成订单按模式一撮合订单
userConfig["matchingMode"]= 2
////tick的数据格式,table或dict
//
userConfig["stockDividend"]=table(["600467.XSHG"] as symbol,[2023.04.01] as endDate,[2023.01.01] as annDate,[2023.02.01] as recordDate,
[2023.02.02] as exDate,[2023.02.02] as payDate,[2023.02.02] as divListDate,[0.] as bonusRatio,
[0.02] as capitalConversion,[0.05] as afterTaxCashDiv,[0.01] as allotPrice,[0.] as allotRatio)
////tick的数据格式,table或dict
userConfig["msgAsTable"]= false
strategyName="gridStrategy"
// 网格间距(百分数)
userParam=dict(STRING,DOUBLE)
userParam["alpha"] = 0.01
// 回落间距(百分数)
userParam["beta"] = 0.005
// 每格交易金额
userParam["M"] = 100000
try{dropBacktestEngine(strategyName)}catch(ex){print ex}
engine = createBacktestEngine(strategyName, userConfig,,initialize{,userParam}, beforeTrading,onBar,,onOrder,onTrade,afterTrading,finalized)
go
// step 3:获取数据与执行策略回测
// 模拟数据
// minData见附件
name = ["symbol","tradeTime","open","low","high","close","volume","amount","upLimitPrice","downLimitPrice","prevClosePrice","signal"]
type = ["STRING","TIMESTAMP","DOUBLE","DOUBLE","DOUBLE","DOUBLE","LONG","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE[]"]
schemaTb = table(name,type)
minData= loadText(filename="/home/ddb/data/minData.csv",schema=schemaTb)
//开始执行回测
timer appendQuotationMsg(engine,minData)
// step 4:获取回测结果
//成交明细
tradeDetails=getTradeDetails(engine)
//查询当前的未成交(未完成)订单列表
openOrders=getOpenOrders(long(engine))
//每日持仓
dailyPosition=getDailyPosition(long(engine))
//未成交订单明细
openOrders=tradeDetails[tradeDetails.orderStatus==-3]
//回测结果综合展示
returnSummary=getReturnSummary(long(engine))
附件:minData.csv