资源加载中... loading...

回测系统

当您完成了一个量化交易策略的设计工作后,怎么才能知道您这个策略的逻辑、策略收益方向等基本情况?当然我们不能直接拿真金白银去交易市场上跑策略,我们可以用历史数据来测试您的策略。看看您的策略在历史数据中盈利如何。

回测系统模式

优宽量化交易平台将回测模式分为实盘级 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可视化编写设计的策略进行回测测试。 JavaScriptC++策略回测是在浏览器端进行,JavaScriptC++语言的策略在实盘、回测运行时不用安装任何其它软件、库或模块。 Python语言的策略回测是在托管者上进行,可以在优宽量化的公共服务器上回测,也可以在用户自己的托管者上回测。实盘和回测都依赖托管者所在系统上安装的Python环境,如果需要使用一些库,需要自行安装,优宽量化的公共服务器上只支持常用的Python库。

回测系统支持的交易所

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

回测系统参数调优

优宽量化交易平台回测系统参数调优功能是在回测时根据各个参数的调优选项设置参数组合,勾选策略参数右侧的调优选项即可出现调优设置。

参数调优截图

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

根据最小值最大值步长设置,生成参数组合。回测系统遍历这些参数组合进行回测(即每种参数组合都回测一遍)。策略参数只有类型为**数字型(number)**的参数才可以在回测系统中进行参数调优设置。

保存回测设置

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

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

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

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

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

My语言:

(*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语言:

/*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
period K线数据的周期(毫秒) 例如:60000为1分钟周期
depth 深度档数 1-20
trades 是否需要分笔数据 真(1)/假(0)
from 开始时间 unix时间戳
to 结束时间 unix时间
detail 请求数据的品种详细信息 为true,表示需要由自定义数据源提供。优宽量化交易平台回测系统向自定义数据源发送的请求固定为:detail=true
custom 可以忽略该参数

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

// 模拟级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级别回测,以下是数据范例:

    {
        "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为价格倒序)。

    // 不含分笔数据
    {
        "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 交易所对象Id Futures_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字段。

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

自定义数据源范例

指定数据源地址,例如:http://120.24.2.20:9090/data。自定义数据源服务程序使用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范例:

/*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线周期。

回测页面快捷键

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

回测数据下载

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

回测系统夏普算法

回测系统夏普算法源码:

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
    }
}
策略编辑器 策略入口函数