输入/搜索内容
欢迎使用优宽量化交易平台
编程语言
JavaScript
TypeScript
Python
C++
My语言(麦语言)
PINE语言
Blockly可视化
Workflow工作流
支持的协议
密钥安全性
实盘
策略库
托管者
部署托管者
一键租用托管者
手动部署托管者
托管者操作注意事项
全局指定IP地址
命令行版本托管者程序的参数
实盘数据迁移
托管者监控
交易所
策略编辑器
回测系统
策略入口函数
策略框架与API函数
模板类库
策略参数
交互控件
商品期货
期权交易
股票证券
C++策略编写说明
JavaScript策略编写说明
内置库
扩展API接口
MCP 服务
交易终端
数据探索
Alpha因子分析工具
调试工具
远程编辑
完整策略的导入与导出
多语言支持
实盘、策略分组
实盘展示
策略分享与出租
实盘消息推送
实盘报错、异常退出的常见原因
交易所特殊说明、兼容记录

当您完成量化交易策略的设计后,如何验证策略的逻辑正确性、收益预期等关键指标?显然不能直接使用真实资金在市场中测试。正确的做法是使用历史数据对策略进行回测,通过分析策略在历史行情中的表现来评估其盈利能力和风险特征。

优宽量化交易平台将回测模式分为实盘级 Tick回测和模拟级 Tick回测。实盘级 Tick回测完全基于完整的历史数据进行回测;模拟级 Tick回测则根据真实K线数据生成tick数据来进行回测。两者都是基于真实历史数据进行回测的,但实盘级 Tick回测的数据更精准,结果更加可信。优宽量化回测机制说明。需要注意的是,回测仅反映策略在历史数据下的表现,历史数据并不能完全代表未来的行情,因此对待回测结果应保持理性、客观的态度。

模拟级 Tick回测根据底层K线周期生成模拟的tick数据,每个底层K线周期上最多生成12个回测时间点。而实盘级 Tick回测使用的是真实收集的逐秒tick数据,数据量大,回测速度较慢,因此不适合回测特别长的时间范围。优宽量化的回测机制允许策略在一根K线上进行多次交易,避免了仅能在收盘价成交的局限性,在保证精准度的同时兼顾了回测速度。

  • 模拟级 Tick
    模拟级 Tick回测是根据回测系统的底层K线数据,按照特定算法在给定的底层K线Bar的最高价、最低价、开盘价、收盘价构成的价格框架内模拟出tick数据进行回测,作为回测时间序列上的实时tick数据,在策略程序调用接口时返回。具体可参考:优宽量化模拟级别回测机制说明

  • 实盘级 Tick
    实盘级别回测使用真实的tick级别数据在Bar的时间序列中进行。对于基于tick级别数据的策略而言,使用实盘级别回测更贴近真实交易环境。实盘级别回测的tick是真实记录的数据,并非模拟生成。支持深度数据、市场成交记录数据回放,支持自定义深度,支持分笔数据。实盘级别回测数据最大支持50MB,在数据上限内不限制回测时间范围。如需尽可能增大回测时间范围,可以降低深度档位数值设置,不使用分笔数据以扩展回测时间范围。调用GetDepthGetTrades函数获取回放行情数据。在时间轴上某个行情数据时刻,调用GetTickerGetTradesGetDepthGetRecords,不会多次推动时间在回测时间轴上移动(不会触发跳转到下一个行情数据时刻)。对于以上某个函数的重复调用,将推动回测时间在回测时间轴上移动(跳转到下一个行情数据时刻)。回测时使用实盘级别回测不宜选择过早的时间段,因为过早的时间段可能没有实盘级别数据。

实盘级Tick模拟级Tick模式的回测系统成交撮合机制:订单成交撮合按照见价成交、全量成交的原则进行。因此回测系统中无法测试部分成交的场景。

回测系统支持:JavaScriptTypeScriptPythonC++PINEMy语言Blockly可视化、Workflow工作流编写设计的策略进行回测测试。
JavaScriptC++策略回测在浏览器端进行,使用JavaScriptC++语言编写的策略在实盘和回测运行时无需安装任何其他软件、库或模块。
Python语言的策略回测在托管者上进行,可以在优宽量化的公共服务器上回测,也可以在用户自己的托管者上回测。实盘和回测都依赖托管者所在系统上安装的Python环境,如需使用特定库,需要自行安装。优宽量化的公共服务器仅支持常用的
Python
库。
Workflow工作流策略支持回测,可以可视化查看节点执行状态和数据流转。

  • 商品期货:支持大连商品交易所、郑州商品交易所、上海期货交易所、中国金融期货交易所等国内主要期货交易所的全品种期货数据,暂不支持商品期权数据。
  • 股票证券:目前仅支持有限的数据,股票数据仅限于日线级别的K线回测数据。

优宽量化交易平台的回测系统参数调优功能允许在回测时根据各参数的调优选项设置参数组合。勾选策略参数右侧的调优选项即可显示调优设置界面。

参数调优截图

  • 最小值:设定参数的起始值。
  • 最大值:设定参数递增后的最大值。
  • 步长:参数的递增步进值。
  • 并发线程:
    参数调优时,设置各回测参数组合并发执行的线程数。该选项仅支持JavaScriptPINEMy语言策略的参数调优,不支持模板参数调优。

系统根据最小值最大值步长的设置生成参数组合,并遍历这些参数组合进行回测(即对每种参数组合执行一次回测)。策略参数仅支持**数字型(number)**参数在回测系统中进行参数调优设置。

当设置好这些参数配置后即可按照设定进行策略回测,那么如何保存这些已设置的配置信息呢?

  • 1、可以使用策略编辑页面的「保存回测设置」按钮将所有回测配置信息(包含回测设置、策略参数设置)以代码形式记录在策略源码中。
  • 2、在策略编辑页面点击「保存策略」按钮保存策略时,平台会自动记录当前的回测设置、策略参数配置等信息。

回测系统如何载入回测配置?

  • 1、刷新策略编辑页面或重新打开策略编辑页面时,系统优先自动载入通过「保存回测设置」按钮记录的回测配置信息。
  • 2、如果当前策略代码中没有以注释形式backtest记录的回测配置信息(通过「保存回测设置」按钮保存在策略代码中),回测系统将自动配置回测设置为该策略最后一次点击「保存策略」按钮时的回测配置信息。
  • 3、如果在策略编辑页面中修改了策略代码开头部分以注释形式记录的回测配置信息,需要将更新后的回测配置信息同步到策略回测界面的选项中,可以点击策略编辑区域backtest上方的「回测设置」按钮。

示例

  • 点击「保存回测设置」后,JavaScript/Python/C++/My语言/PINE语言的策略保存回测设置到策略代码时,格式略有差异:

    javascript
    /*backtest start: 2022-09-13 09:00:00 end: 2023-09-19 15:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}] */
    python
    '''backtest start: 2022-09-13 09:00:00 end: 2023-09-19 15:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}] '''
    c++
    /*backtest start: 2022-09-13 09:00:00 end: 2023-09-19 15:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}] */
  • My语言:

    mylang
    (*backtest start: 2022-09-13 09:00:00 end: 2023-09-19 15:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}] args: [["ContractType","rb888",325065]] *)
  • PINE语言:

    pine
    /*backtest start: 2022-09-13 09:00:00 end: 2023-09-19 15:00:00 period: 1d basePeriod: 1h exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","depthDeep":20}] args: [["ContractType","rb888",360008]] */

优宽量化交易平台的回测系统支持自定义数据源。回测系统使用 GET 方法请求自定义的 URL(可公开访问的网址)来获取外部数据源进行回测,附加的请求参数如下:

参数意义说明
symbol品种名称如:FUTURES_CNY.MA501
eid交易所标识如:Futures_CTP
round数据精度为 true 时,表示由自定义数据源返回的数据中定义具体精度。优宽量化交易平台回测系统向自定义数据源发送的请求固定为:round=true
periodK线数据周期(毫秒)例如:60000 表示1分钟周期
depth深度档位数1-20
trades是否需要逐笔成交数据真(1)/假(0)
from开始时间Unix 时间戳
to结束时间Unix 时间戳
detail请求品种详细信息为 true 时,表示需要由自定义数据源提供。优宽量化交易平台回测系统向自定义数据源发送的请求固定为:detail=true
custom--可忽略此参数

当交易所对象的数据源设置为自定义数据源(feeder)时,回测系统向自定义数据源服务发送请求的示例:

url
// 模拟级Tick http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_CTP&from=1719745260&period=60000&round=true&symbol=FUTURES_CNY.MA501&to=1720281600&trades=0 // 实盘级Tick http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_CTP&from=1719763200&period=1000&round=true&symbol=FUTURES_CNY.MA501&to=1720281600&trades=0

返回的格式必须为以下两种格式之一(系统自动识别):

  • 模拟级 Tick,以下是JSON数据示例:
    普通的Bar级别回测,以下是数据示例:

    json
    { "detail": { "alias": "MA501", "baseCurrency": "FUTURES", "basePrecision": 1, "contractType": "MA501", "eid": "Futures_CTP", "info": { "CombinationType": 48, "CreateDate": 20240116, "DeliveryMonth": 1, "DeliveryYear": 1501, "EndDelivDate": 20250114, "ExchangeID": "CZCE", "ExchangeInstID": "MA501", "ExpireDate": 20250114, "InstLifePhase": 49, "InstrumentID": "MA501", "InstrumentName": "甲醇1月", "IsTrading": 1, "LongMarginRatio": 0.08, "MaxLimitOrderVolume": 1000, "MaxMarginSideAlgorithm": 48, "MaxMarketOrderVolume": 200, "MinLimitOrderVolume": 1, "MinMarketOrderVolume": 1, "OpenDate": 20240116, "OptionsType": 0, "PositionDateType": 50, "PositionType": 50, "PriceTick": 1, "ProductClass": 49, "ProductID": "MA", "ShortMarginRatio": 0.08, "StartDelivDate": 0, "StrikePrice": 0, "UnderlyingInstrID": "", "UnderlyingMultiple": 1, "VolumeMultiple": 10 }, "marginCurrency": "CNY", "marginLevel": 12, "maxNotional": 10000000, "maxQty": 1000, "minNotional": 1, "minQty": 1, "priceTick": 1, "quoteCurrency": "CNY", "quotePrecision": 0, "symbol": "MA501", "volumeTick": 1 }, "schema": ["time", "open", "high", "low", "close", "vol", "position"], "data": [ [1719795600000, 2632, 2633, 2621, 2625, 13070, 1720510], // 2024-07-01 09:00:00 [1719795660000, 2625, 2625, 2621, 2623, 4280, 1720940], // 2024-07-01 09:01:00 [1719795720000, 2623, 2626, 2622, 2622, 5320, 1722310], // 2024-07-01 09:02:00 [1719795780000, 2622, 2625, 2620, 2625, 3480, 1722160], [1719795840000, 2624, 2624, 2622, 2623, 2220, 1723150], [1719795900000, 2623, 2624, 2620, 2620, 3080, 1722840], [1719795960000, 2621, 2622, 2620, 2620, 3090, 1723850] ] }
  • 实盘级 Tick,以下是JSON数据示例:
    Tick级回测的数据(包含盘口深度信息,深度格式为[价格, 量]的数组。可有多级深度,asks为价格升序,bids为价格降序)。

    json
    // 不含分笔数据 { "detail": { "alias": "MA501", "baseCurrency": "FUTURES", "basePrecision": 1, "contractType": "MA501", "eid": "Futures_CTP", "info": { "CombinationType": 48, "CreateDate": 20240116, "DeliveryMonth": 1, "DeliveryYear": 1501, "EndDelivDate": 20250114, "ExchangeID": "CZCE", "ExchangeInstID": "MA501", "ExpireDate": 20250114, "InstLifePhase": 49, "InstrumentID": "MA501", "InstrumentName": "甲醇1月", "IsTrading": 1, "LongMarginRatio": 0.08, "MaxLimitOrderVolume": 1000, "MaxMarginSideAlgorithm": 48, "MaxMarketOrderVolume": 200, "MinLimitOrderVolume": 1, "MinMarketOrderVolume": 1, "OpenDate": 20240116, "OptionsType": 0, "PositionDateType": 50, "PositionType": 50, "PriceTick": 1, "ProductClass": 49, "ProductID": "MA", "ShortMarginRatio": 0.08, "StartDelivDate": 0, "StrikePrice": 0, "UnderlyingInstrID": "", "UnderlyingMultiple": 1, "VolumeMultiple": 10 }, "marginCurrency": "CNY", "marginLevel": 12, "maxNotional": 10000000, "maxQty": 1000, "minNotional": 1, "minQty": 1, "priceTick": 1, "quoteCurrency": "CNY", "quotePrecision": 0, "symbol": "MA501", "volumeTick": 1 }, "schema": ["time", "asks", "bids", "close", "vol", "position"], "data": [ [1719795601778, [[2633, 50]], [[2631, 50]], 2632, 110410, 1718490], [1719795602192, [[2632, 120]], [[2631, 50]], 2632, 110410, 1718490], [1719795603873, [[2631, 20]], [[2630, 600]], 2631, 110780, 1718790], [1719795604769, [[2633, 120]], [[2630, 490]], 2631, 111300, 1718860], [1719795605661, [[2632, 200]], [[2631, 30]], 2632, 111750, 1718880] ] }
字段说明
schema指定data数组中各列的属性,区分大小写,仅限于 time, open, high, low, close, vol, asks, bids, trades
data按schema指定的列顺序保存数据的数组
detail商品期货品种需要提供的属性信息

detail字段

字段说明例子
alias合约代码rb2501
baseCurrency交易品种FUTURES
basePrecision交易品种精度1
contractType合约代码rb2501
eid交易所对象IdFutures_CTP
info合约详细信息其中记录了合约的上市日期、交割日期、合约乘数、价格跳动单位等信息。
marginCurrency保证金币种CNY
marginLevel杠杆倍数该数据与合约具体的保证金率相关,一般不可修改
maxNotional单笔最大下单金额10000000
maxQty单笔最大下单数量1000
minNotional单笔最小下单金额1
minQty单笔最小下单数量1
priceTick价格跳动单位--
quoteCurrency计价货币CNY
quotePrecision计价货币精度0
symbol合约代码rb2501
volumeTick下单量最小变动单位1

特殊的列属性asksbidstrades

字段说明备注
asks / bids[[价格, 数量], ...]例如实盘级 Tick数据示例中的数据:[[9531300, 10]]
trades[[时间, 方向(0:买,1:卖), 价格, 数量], ...]例如实盘级 Tick数据示例中的数据:[[1564315200000, 0, 9531300, 10]]

detail字段中info字段值内容与exchange.SetContractType()函数返回的数据Info字段一致。

detail字段中timeLine字段说明:
当策略代码中设置的合约代码为主力连续合约(例如:MA888)或指数合约(例如:MA000)时,自定义数据源响应的数据的detail中还需要增加一个timeLine字段。

json
// timeLine字段值 [ { "begin": 1451836800000, "end": 1460013300000, "symbol": "MA605" }, { "begin": 1460034000000, "end": 1470640500000, "symbol": "MA609" } // ... ]

指定数据源地址,例如:http://120.24.2.20:9090/data。自定义数据源服务程序使用Golang编写:

golang
package main import ( "fmt" "net/http" "encoding/json" ) func Handle (w http.ResponseWriter, r *http.Request) { // e.g. set on backtest DataSourse: http://xxx.xx.x.xx:9090/data // r.URL: /data?custom=0&depth=20&detail=true&eid=Futures_CTP&from=1719745260&period=60000&round=true&symbol=FUTURES_CNY.MA501&to=1720281600&trades=0 fmt.Println("request:", r) // response defer func() { // response data /* e.g. data { "detail": { "alias": "MA501", "baseCurrency": "FUTURES", "basePrecision": 1, "contractType": "MA501", "eid": "Futures_CTP", "info": { "CombinationType": 48, "CreateDate": 20240116, "DeliveryMonth": 1, "DeliveryYear": 1501, "EndDelivDate": 20250114, "ExchangeID": "CZCE", "ExchangeInstID": "MA501", "ExpireDate": 20250114, "InstLifePhase": 49, "InstrumentID": "MA501", "InstrumentName": "甲醇1月", "IsTrading": 1, "LongMarginRatio": 0.08, "MaxLimitOrderVolume": 1000, "MaxMarginSideAlgorithm": 48, "MaxMarketOrderVolume": 200, "MinLimitOrderVolume": 1, "MinMarketOrderVolume": 1, "OpenDate": 20240116, "OptionsType": 0, "PositionDateType": 50, "PositionType": 50, "PriceTick": 1, "ProductClass": 49, "ProductID": "MA", "ShortMarginRatio": 0.08, "StartDelivDate": 0, "StrikePrice": 0, "UnderlyingInstrID": "", "UnderlyingMultiple": 1, "VolumeMultiple": 10 }, "marginCurrency": "CNY", "marginLevel": 12, "maxNotional": 10000000, "maxQty": 1000, "minNotional": 1, "minQty": 1, "priceTick": 1, "quoteCurrency": "CNY", "quotePrecision": 0, "symbol": "MA501", "volumeTick": 1 }, "schema": ["time", "open", "high", "low", "close", "vol", "position"], "data": [ [1719795600000, 2632, 2633, 2621, 2625, 13070, 1720510], // 2024-07-01 09:00:00 [1719795660000, 2625, 2625, 2621, 2623, 4280, 1720940], // 2024-07-01 09:01:00 [1719795720000, 2623, 2626, 2622, 2622, 5320, 1722310], // 2024-07-01 09:02:00 [1719795780000, 2622, 2625, 2620, 2625, 3480, 1722160], [1719795840000, 2624, 2624, 2622, 2623, 2220, 1723150], [1719795900000, 2623, 2624, 2620, 2620, 3080, 1722840], [1719795960000, 2621, 2622, 2620, 2620, 3090, 1723850] ] } */ // /* 模拟级Tick ret := map[string]interface{}{ "detail": map[string]interface{}{ "alias": "MA501", "baseCurrency": "FUTURES", "basePrecision": 1, "contractType": "MA501", "eid": "Futures_CTP", "info": map[string]interface{}{ "CombinationType": 48, "CreateDate": 20240116, "DeliveryMonth": 1, "DeliveryYear": 1501, "EndDelivDate": 20250114, "ExchangeID": "CZCE", "ExchangeInstID": "MA501", "ExpireDate": 20250114, "InstLifePhase": 49, "InstrumentID": "MA501", "InstrumentName": "甲醇1月", "IsTrading": 1, "LongMarginRatio": 0.08, "MaxLimitOrderVolume": 1000, "MaxMarginSideAlgorithm": 48, "MaxMarketOrderVolume": 200, "MinLimitOrderVolume": 1, "MinMarketOrderVolume": 1, "OpenDate": 20240116, "OptionsType": 0, "PositionDateType": 50, "PositionType": 50, "PriceTick": 1, "ProductClass": 49, "ProductID": "MA", "ShortMarginRatio": 0.08, "StartDelivDate": 0, "StrikePrice": 0, "UnderlyingInstrID": "", "UnderlyingMultiple": 1, "VolumeMultiple": 10, }, "marginCurrency": "CNY", "marginLevel": 12, "maxNotional": 10000000, "maxQty": 1000, "minNotional": 1, "minQty": 1, "priceTick": 1, "quoteCurrency": "CNY", "quotePrecision": 0, "symbol": "MA501", "volumeTick": 1, }, "schema": []string{"time", "open", "high", "low", "close", "vol", "position"}, "data": []interface{}{ []int64{1719795600000, 2632, 2633, 2621, 2625, 13070, 1720510}, []int64{1719795660000, 2625, 2625, 2621, 2623, 4280, 1720940}, []int64{1719795720000, 2623, 2626, 2622, 2622, 5320, 1722310}, []int64{1719795780000, 2622, 2625, 2620, 2625, 3480, 1722160}, []int64{1719795840000, 2624, 2624, 2622, 2623, 2220, 1723150}, []int64{1719795900000, 2623, 2624, 2620, 2620, 3080, 1722840}, []int64{1719795960000, 2621, 2622, 2620, 2620, 3090, 1723850}, }, } // */ /* 实盘级Tick ret := map[string]interface{}{ "detail": map[string]interface{}{ "alias": "MA501", "baseCurrency": "FUTURES", "basePrecision": 1, "contractType": "MA501", "eid": "Futures_CTP", "info": map[string]interface{}{ "CombinationType": 48, "CreateDate": 20240116, "DeliveryMonth": 1, "DeliveryYear": 1501, "EndDelivDate": 20250114, "ExchangeID": "CZCE", "ExchangeInstID": "MA501", "ExpireDate": 20250114, "InstLifePhase": 49, "InstrumentID": "MA501", "InstrumentName": "甲醇1月", "IsTrading": 1, "LongMarginRatio": 0.08, "MaxLimitOrderVolume": 1000, "MaxMarginSideAlgorithm": 48, "MaxMarketOrderVolume": 200, "MinLimitOrderVolume": 1, "MinMarketOrderVolume": 1, "OpenDate": 20240116, "OptionsType": 0, "PositionDateType": 50, "PositionType": 50, "PriceTick": 1, "ProductClass": 49, "ProductID": "MA", "ShortMarginRatio": 0.08, "StartDelivDate": 0, "StrikePrice": 0, "UnderlyingInstrID": "", "UnderlyingMultiple": 1, "VolumeMultiple": 10, }, "marginCurrency": "CNY", "marginLevel": 12, "maxNotional": 10000000, "maxQty": 1000, "minNotional": 1, "minQty": 1, "priceTick": 1, "quoteCurrency": "CNY", "quotePrecision": 0, "symbol": "MA501", "volumeTick": 1, }, "schema": []string{"time", "asks", "bids", "close", "vol", "position"}, "data": []interface{}{ []interface{}{1719795601778, []interface{}{[]int64{2633, 50}}, []interface{}{[]int64{2631, 50}}, 2632, 110410, 1718490}, []interface{}{1719795602192, []interface{}{[]int64{2632, 120}}, []interface{}{[]int64{2631, 50}}, 2632, 110410, 1718490}, []interface{}{1719795603873, []interface{}{[]int64{2631, 20}}, []interface{}{[]int64{2630, 600}}, 2631, 110780, 1718790}, []interface{}{1719795604769, []interface{}{[]int64{2633, 120}}, []interface{}{[]int64{2630, 490}}, 2631, 111300, 1718860}, []interface{}{1719795605661, []interface{}{[]int64{2632, 200}}, []interface{}{[]int64{2631, 30}}, 2632, 111750, 1718880}, }, } */ b, _ := json.Marshal(ret) w.Write(b) }() } func main () { fmt.Println("listen http://localhost:9090") http.HandleFunc("/data", Handle) http.ListenAndServe(":9090", nil) }

测试策略,JavaScript示例:

javascript
/*backtest start: 2024-07-01 00:00:00 end: 2024-07-07 00:00:00 period: 1m basePeriod: 1m exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","feeder":"http://120.24.2.20:9090/data"}] */ function main() { // 对于测试代码,我们通过判断exchange.IO("status")函数,连接成功后执行测试代码,区别于商品期货策略的一般架构 while (!exchange.IO("status")) { Sleep(1000) } // 设置合约为MA501 exchange.SetContractType("MA501") // 获取ticker数据 var ticker = exchange.GetTicker() // 获取records数据,即K线数据 var records = exchange.GetRecords() // 打印数据 Log(ticker) Log(records) }

优宽量化交易平台开源了JavaScript语言和Python语言的本地回测引擎,支持在回测时设置底层K线周期。

以Python语言为例,简述本地回测引擎的使用方法:

python
'''backtest start: 2024-10-17 09:00:00 end: 2025-10-16 15:00:00 period: 1d basePeriod: 1d exchanges: [{"eid":"Futures_CTP","currency":"FUTURES","balance":30000000}] ''' # Part 1 ----------------------------------- # 初始化回测引擎,backtest 为回测引擎配置信息,与优宽平台线上回测系统配置一致 # 通过 __doc__ 读取上方的配置字符串并初始化回测环境 from fmz import * task = VCtx(__doc__) # initialize backtest engine from __doc__ # End ----------------------------------- # Part 2 ----------------------------------- # 以下为待测试的策略代码示例(可以从优宽平台复制完整的策略代码) # 注意:仅复制策略代码时不包含参数设计、交互设计等其他配置内容 def onTick(): ticker = _C(exchange.GetTicker) LogStatus(_D(), ticker.Last) def main(): exchange.SetContractType("rb888") Log(exchange.GetAccount()) while True: onTick() Sleep(1000) # End ----------------------------------- # Part 3 ----------------------------------- # 执行回测并捕获结束信号,回测结束时会触发 EOF 异常 # 捕获异常后可以输出回测结果数据或展示回测图表 try: main() except: print("Strategy testing completed.") print(task.Join(False)) # print backtest result # task.Show() # or show backtest chart # End -----------------------------------

  • 策略编辑页面和策略回测页面切换的快捷键
    使用Ctrl + ,键切换回测页面和策略编辑页面,按住Ctrl键后,单按,键。
  • 策略保存的快捷键
    使用Ctrl + s键保存策略。
  • 启动回测的快捷键
    使用Ctrl + b键启动回测。

  • 回测系统日志数据下载
    打开具体策略,切换到「回测页面」进行策略回测。回测结束后,在显示的「状态信息」栏右上角有「下载表格」按钮,点击即可下载回测结束时状态栏数据的CSV格式文件。
  • 回测系统状态栏数据下载
    打开具体策略,切换到「回测页面」进行策略回测。回测结束后,在显示的「日志信息」栏右上角有「下载表格」按钮,点击即可下载回测日志数据的CSV格式文件。

回测系统夏普比率算法源代码:

javascript
function returnAnalyze(totalAssets, profits, ts, te, period, yearDays) { // force by days period = 86400000 if (profits.length == 0) { return null } var freeProfit = 0.03 // 0.04 var yearRange = yearDays * 86400000 var totalReturns = profits[profits.length - 1][1] / totalAssets var annualizedReturns = (totalReturns * yearRange) / (te - ts) // MaxDrawDown var maxDrawdown = 0 var maxAssets = totalAssets var maxAssetsTime = 0 var maxDrawdownTime = 0 var maxDrawdownStartTime = 0 var winningRate = 0 var winningResult = 0 for (var i = 0; i < profits.length; i++) { if (i == 0) { if (profits[i][1] > 0) { winningResult++ } } else { if (profits[i][1] > profits[i - 1][1]) { winningResult++ } } if ((profits[i][1] + totalAssets) > maxAssets) { maxAssets = profits[i][1] + totalAssets maxAssetsTime = profits[i][0] } if (maxAssets > 0) { var drawDown = 1 - (profits[i][1] + totalAssets) / maxAssets if (drawDown > maxDrawdown) { maxDrawdown = drawDown maxDrawdownTime = profits[i][0] maxDrawdownStartTime = maxAssetsTime } } } if (profits.length > 0) { winningRate = winningResult / profits.length } // trim profits var i = 0 var datas = [] var sum = 0 var preProfit = 0 var perRatio = 0 var rangeEnd = te if ((te - ts) % period > 0) { rangeEnd = (parseInt(te / period) + 1) * period } for (var n = ts; n < rangeEnd; n += period) { var dayProfit = 0.0 var cut = n + period while (i < profits.length && profits[i][0] < cut) { dayProfit += (profits[i][1] - preProfit) preProfit = profits[i][1] i++ } perRatio = ((dayProfit / totalAssets) * yearRange) / period sum += perRatio datas.push(perRatio) } var sharpeRatio = 0 var volatility = 0 if (datas.length > 0) { var avg = sum / datas.length; var std = 0; for (i = 0; i < datas.length; i++) { std += Math.pow(datas[i] - avg, 2); } volatility = Math.sqrt(std / datas.length); if (volatility !== 0) { sharpeRatio = (annualizedReturns - freeProfit) / volatility } } return { totalAssets: totalAssets, yearDays: yearDays, totalReturns: totalReturns, annualizedReturns: annualizedReturns, sharpeRatio: sharpeRatio, volatility: volatility, maxDrawdown: maxDrawdown, maxDrawdownTime: maxDrawdownTime, maxAssetsTime: maxAssetsTime, maxDrawdownStartTime: maxDrawdownStartTime, winningRate: winningRate } }