Backtest

通过 DolphinDB 的 Backtest 插件,用户可以输入历史行情数据并应用自己的交易策略,来帮助制定和优化交易策略。

安装插件

版本要求

DolphinDB Server 2.00.12 及更高版本,支持 X86-64 的 Linux 和 Windows。

安装步骤

  1. 在 DolphinDB 客户端中使用 listRemotePlugins 命令查看插件仓库中的插件信息。

    注意:仅展示当前操作系统和 server 版本支持的插件。若无预期插件,可自行编译(请自行选择对应分支下的插件)或在 DolphinDB 用户社区进行反馈。

    login("admin", "123456")
    listRemotePlugins()
  2. 使用 installPlugin 命令完成插件安装。

    installPlugin("Backtest")
  3. 使用 loadPlugin 命令加载插件。

    loadPlugin("Backtest")

插件依赖

回测引擎插件内部依赖模拟撮合引擎插件,因此加载回测引擎之前需要先加载模拟撮合引擎,该插件同样可以通过插件市场安装。

  1. 使用 installPlugin 命令完成模拟撮合引擎插件安装。

    installPlugin("MatchingEngineSimulator")
  2. 使用 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
frequencyfrequency>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 的表结构如下:

nametype备注
symbolSYMBOL股票代码(上交所以".XSHG"结尾,深交所以"XSHE"结尾)
symbolSourceSTRING"XSHG"(上交所)或者"XSHE"(深交所)
timestampTIMESTAMP
sourceTypeINT0代表委托数据entrust;1代表成交表 trade
orderTypeINTentrust:1市价,2限价,3本方最优,10撤单(仅上交所,即上交所撤单记录在entrust中);trade:0成交,1撤单(仅深交所,即深交所撤单记录在 trade中)
priceDOUBLE订单价格
qtyLONG订单数量
buyNoLONGtrade 对应其原始数据;entrust 中的委托单号填充
sellNoLONGtrade 对应其原始数据;entrust 中的委托单号填充
directionINT1(买 )or 2(卖)
channelNoINT通道号
seqNumLONG逐笔数据序号

逐笔行情时 snapshot 表如下:

nametype备注
symbolSYMBOL股票代码(上交所以".XSHG"结尾,深交所以"XSHE"结尾)
symbolSourceSTRING"XSHG"(上交所)或者"XSHE"(深交所)
timestampTIMESTAMP时间戳
lastPriceDOUBLE最新成交价
upLimitPriceDOUBLE涨停价
downLimitPriceDOUBLE跌停价
totalBidQtyLONG区间买量
totalOfferQtyLONG区间卖量
bidPriceDOUBLE委买价格列表
bidQtyLONG委买量列表
offerPriceDOUBLE委卖价格列表
offerQtyLONG委卖量列表
signalDOUBLE指标列表
seqNumLONG逐笔数据序号
prevClosePriceDOUBLE前收盘价

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 两个字段)

nametype备注
symbolSYMBOL股票代码(上交所以".XSHG"结尾,深交所以"XSHE"结尾)
symbolSourceSTRING"XSHG"(上交所)或者"XSHE"(深交所)
timestampTIMESTAMP时间戳
lastPriceDOUBLE最新成交价
upLimitPriceDOUBLE涨停价
downLimitPriceDOUBLE跌停价
totalBidQtyLONG区间买量
totalOfferQtyLONG区间卖量
bidPriceDOUBLE委买价格列表
bidQtyLONG委买量列表
offerPriceDOUBLE委卖价格列表
offerQtyLONG委卖量列表
tradePriceDOUBLEdataType = 2 时才有
tradeQtyLONGdataType = 2 时才有
signalDOUBLE指标列表
prevClosePriceDOUBLE前收盘价

引擎接收到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)
  1. 标的代码symbol必须带有交易所标识(".XSHG",".XSHE")结尾,如600000.XSHG,不然报错。
  2. 引擎接收到symbol为”END”时,表示策略回测结束
  3. 涨停价 upLimitPrice 不为0时,委托买单价格大于等于涨停价会被拒单
  4. 跌停价 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 对象包含字段如下:

nametype备注
symbolSYMBOL股票代码
symbolSourceSTRING
timestampTIMESTAMP
sourceTypeINT0代表委托数据entrust;1代表成交表trade
orderTypeINTentrust:1市价;2限价;3本方最优;10撤单(仅上交所,即上交所撤单记录在entrust中);trade:0成交;1撤单(仅深交所,即深交所撤单记录在trade中)
priceDOUBLE订单价格
qtyLONG订单数量
buyNoLONG
sellNoLONG
directionINT1(买 )or 2(卖)
channelNoINT通道号
seqNumLONG逐笔数据序号

快照行情回调函数onSnapshot

contextDict 为上下文,msg 为 snapShot 数据,为表或者字典。

字典是,包含 symbol 为 key 值的 snapShot 数据字典,每个 snapShot 对象包含字段如下:

nametype备注
symbolSYMBOL股票标的
symbolSourceSTRING"XSHG"(上交所)或者"XSHE"(深交所)
timestampTIMESTAMP时间戳
lastPriceDOUBLE最新成交价
upLimitPriceDOUBLE涨停价
downLimitPriceDOUBLE跌停价
totalBidQtyLONG区间买量
totalOfferQtyLONG区间卖量
bidPriceDOUBLE委买价格列表
bidQtyLONG委买量列表
offerPriceDOUBLE委卖价格列表
offerQtyLONG委卖量列表
signalDOUBLE

K线行情回调函数onBar

contextDict 为上下文,msg 为K线数据,为表或者字典。

字典是,包含 symbol 为key 值的日频或者分钟频率的 K 线数据字典,每个 K 线包含字段如下:

nametype备注
symbolSYMBOL股票标的
tradeTimeTIMESTAMP交易日
openDOUBLE开盘价
lowDOUBLE最低价
highDOUBLE最高价
closeDOUBLE收盘价
volumeLONG成交量
amountDOUBLE成交额
upLimitPriceDOUBLE涨停价
downLimitPriceDOUBLE跌停价
prevClosePriceDOUBLE前收盘价
signalDOUBLE其他

委托回报onOrder

contextDict 为上下文,orders 为订单信息的字典列表。

名称含义备注
orderId委托订单 idint → 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 五列。

名称类型含义
orderIdLONG订单 ID
timestampTIMESTAMP时间
symbolSTRING股票标的
priceDOUBLE委托价格
totalQtyLONG用户订单数量
openQtyLONG用户订单余量
directionINT1(买 ),2(卖)
isMacthingINT订单是否到达撮合时间
openVolumeWithBetterPriceLONG优于委托价格的行情未成交委托单总量
openVolumeWithWorsePriceLONG次于委托价格的行情未成交委托单总量
openVolumeAtOrderPriceLONG等于委托价格行情未成交委托单总量
priorOpenVolumeAtOrderPriceLONG等于委托价格行情且比自己早的行情未成交委托单总量
depthVolumeWithBetterPriceINT优于委托价格的行情未成交价格档位深度
updateTimeTIMESTAMP最新更新时间

参数

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成交数量
orderStatusorderStatus表示订单状态。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)
betabeta系数covar(deltas(value)\prev(value), deltas(price)\prev(price)) \ std(deltas(price)\prev(price))
alphaa系数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