自定义数据源
发明者量化交易平台的回测系统支持自定义数据源,回测系统使用GET方法请求自定义的URL(可公开访问的网址)来获取外部数据源进行回测,附加的请求参数如下:
| 参数 | 意义 | 说明 |
|---|---|---|
| symbol | 品种名称 | 现货行情数据示例:BTC_USDT,期货行情数据示例:BTC_USDT.swap,期货永续合约资金费率数据示例:BTC_USDT.funding,期货永续合约价格指数数据示例:BTC_USDT.index |
| eid | 交易所 | 例如:OKX、Futures_OKX |
| round | 数据精度 | 为true时,表示由自定义数据源返回的数据中定义具体精度。发明者量化交易平台回测系统向自定义数据源发送的请求固定为:round=true |
| period | K线数据的周期(毫秒) | 例如:60000表示1分钟周期 |
| depth | 深度档数 | 1-20 |
| trades | 是否需要逐笔成交数据 | 真(1)/假(0) |
| from | 开始时间 | unix时间戳 |
| to | 结束时间 | unix时间戳 |
| detail | 请求品种的详细信息 | 为true时,表示需要由自定义数据源提供。发明者量化交易平台回测系统向自定义数据源发送的请求固定为:detail=true |
| custom | -- | 可忽略此参数 |
现货交易所、期货交易所对象的数据源设置为自定义数据源(feeder)时,回测系统向自定义数据源服务发送请求的示例:
url
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Bitget&from=1351641600&period=86400000&round=true&symbol=BTC_USDT&to=1611244800&trades=1
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_OKX&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.swap&to=1611244800&trades=1
数据格式
返回的格式必须为以下两种格式之一(系统自动识别):
- 模拟级Tick,以下是JSON数据示例:json{ "detail": { "eid": "Binance", "symbol": "BTC_USDT", "alias": "BTCUSDT", "baseCurrency": "BTC", "quoteCurrency": "USDT", "marginCurrency": "USDT", "basePrecision": 5, "quotePrecision": 2, "minQty": 0.00001, "maxQty": 9000, "minNotional": 5, "maxNotional": 9000000, "priceTick": 0.01, "volumeTick": 0.00001, "marginLevel": 10 }, "schema":["time", "open", "high", "low", "close", "vol"], "data":[ [1564315200000, 9531300, 9531300, 9497060, 9497060, 787], [1564316100000, 9495160, 9495160, 9474260, 9489460, 338] ] }
- 实盘级Tick,以下是JSON数据示例:
Tick级回测数据(包含盘口深度信息,深度格式为[价格, 数量]的数组。可包含多级深度,asks按价格升序排列,bids按价格降序排列)。json{ "detail": { "eid": "Binance", "symbol": "BTC_USDT", "alias": "BTCUSDT", "baseCurrency": "BTC", "quoteCurrency": "USDT", "marginCurrency": "USDT", "basePrecision": 5, "quotePrecision": 2, "minQty": 0.00001, "maxQty": 9000, "minNotional": 5, "maxNotional": 9000000, "priceTick": 0.01, "volumeTick": 0.00001, "marginLevel": 10 }, "schema":["time", "asks", "bids", "trades", "close", "vol"], "data":[ [1564315200000, [[9531300, 10]], [[9531300, 10]], [[1564315200000, 0, 9531300, 10]], 9497060, 787], [1564316100000, [[9531300, 10]], [[9531300, 10]], [[1564316100000, 0, 9531300, 10]], 9497060, 787] ] }
| 字段 | 说明 |
|---|---|
| detail | 请求数据的品种详细信息,包含计价币名称、交易币名称、精度、最小下单量等 |
| schema | 指定data数组中列的属性,区分大小写。仅限于 time, open, high, low, close, vol, asks, bids, trades |
| data | 按照schema设置的列结构记录的数据 |
detail字段
| 字段 | 说明 |
|---|---|
| eid | 交易所ID,注意同一交易所的现货与期货使用不同的eid |
| symbol | 交易品种代码 |
| alias | 当前交易品种代码在交易所中对应的symbol |
| baseCurrency | 交易币种 |
| quoteCurrency | 计价币种 |
| marginCurrency | 保证金币种 |
| basePrecision | 交易币种精度 |
| quotePrecision | 计价币种精度 |
| minQty | 最小下单量 |
| maxQty | 最大下单量 |
| minNotional | 最小下单金额 |
| maxNotional | 最大下单金额 |
| priceTick | 价格最小变动单位 |
| volumeTick | 下单量最小变动单位 |
| marginLevel | 期货杠杆倍数 |
| contractType | 对于永续合约设置为:swap,回测系统将继续发送资金费率、价格指数请求 |
特殊列属性asks、bids、trades说明:
| 字段 | 说明 | 备注 |
|---|---|---|
| asks / bids | [[价格, 数量], ...] | 例如实盘级 Tick数据示例中的数据:[[9531300, 10]] |
| trades | [[时间, 方向(0:买,1:卖), 价格, 数量], ...] | 例如实盘级 Tick数据示例中的数据:[[1564315200000, 0, 9531300, 10]] |
期货交易所的永续合约回测时,自定义数据源还需要提供额外的资金费率数据和价格指数数据。只有当请求的行情数据返回时,返回结构中的detail字段包含"contractType": "swap"键值对,回测系统才会继续发送资金费率请求。
当回测系统收到资金费率数据后,才会继续发送价格指数数据请求。
资金费率数据结构如下:
json
{
"detail": {
"eid": "Futures_Binance",
"symbol": "BTC_USDT.funding",
"alias": "BTC_USDT.funding",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "",
"basePrecision": 8,
"quotePrecision": 8,
"minQty": 1,
"maxQty": 10000,
"minNotional": 1,
"maxNotional": 100000000,
"priceTick": 1e-8,
"volumeTick": 1e-8,
"marginLevel": 10
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[
1584921600000,
-16795,
-16795,
-16795,
-16795,
0
],
[
1584950400000,
-16294,
-16294,
-16294,
-16294,
0
]
// ...
]
}
- 相邻周期间隔为8小时
- 例如币安资金费率每8小时更新一次,资金费率数据为何是 -16795?
这是因为与K线数据一样,为避免网络传输过程中浮点数精度丢失,数据采用整型表示;资金费率数据也可能为负值。
回测系统发出的资金费率数据请求示例:
url
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.funding&to=1611244800&trades=0
价格指数数据结构如下:
json
{
"detail": {
"eid": "Futures_Binance",
"symbol": "BTC_USDT.index",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"contractType": "index",
"marginCurrency": "USDT",
"basePrecision": 3,
"quotePrecision": 1,
"minQty": 0.001,
"maxQty": 1000,
"minNotional": 0,
"maxNotional": 1.7976931348623157e+308,
"priceTick": 0.1,
"volumeTick": 0.001,
"marginLevel": 10,
"volumeMultiple": 1
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[1584921600000, 58172, 59167, 56902, 58962, 0],
[1584922500000, 58975, 59428, 58581, 59154, 0],
// ...
]
}
回测系统发出的价格指数数据请求示例:
url
http://customserver:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1351641600&period=86400000&round=true&symbol=BTC_USDT.index&to=1611244800&trades=0
自定义数据源范例
指定数据源地址,例如: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
// request: GET http://xxx.xx.x.xx:9090/data?custom=0&depth=20&detail=true&eid=OKX&from=1584921600&period=86400000&round=true&symbol=BTC_USDT&to=1611244800&trades=1
// http://xxx.xx.x.xx:9090/data?custom=0&depth=20&detail=true&eid=Futures_Binance&from=1599958800&period=3600000&round=true&symbol=BTC_USDT.swap&to=1611244800&trades=0
fmt.Println("request:", r)
// response
defer func() {
// response data
/* e.g. data
{
"detail": {
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10
},
"schema": [
"time",
"open",
"high",
"low",
"close",
"vol"
],
"data": [
[1610755200000, 3673743, 3795000, 3535780, 3599498, 8634843151],
[1610841600000, 3599498, 3685250, 3385000, 3582861, 8015772738],
[1610928000000, 3582499, 3746983, 3480000, 3663127, 7069811875],
[1611014400000, 3662246, 3785000, 3584406, 3589149, 7961130777],
[1611100800000, 3590194, 3641531, 3340000, 3546823, 8936842292],
[1611187200000, 3546823, 3560000, 3007100, 3085013, 13500407666],
[1611273600000, 3085199, 3382653, 2885000, 3294517, 14297168405],
[1611360000000, 3295000, 3345600, 3139016, 3207800, 6459528768],
[1611446400000, 3207800, 3307100, 3090000, 3225990, 5797803797],
[1611532800000, 3225945, 3487500, 3191000, 3225420, 8849922692]
]
}
*/
// /* 模拟级Tick
ret := map[string]interface{}{
"detail": map[string]interface{}{
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10,
},
"schema": []string{"time","open","high","low","close","vol"},
"data": []interface{}{
[]int64{1610755200000, 3673743, 3795000, 3535780, 3599498, 8634843151}, // 1610755200000 : 2021-01-16 08:00:00
[]int64{1610841600000, 3599498, 3685250, 3385000, 3582861, 8015772738}, // 1610841600000 : 2021-01-17 08:00:00
[]int64{1610928000000, 3582499, 3746983, 3480000, 3663127, 7069811875},
[]int64{1611014400000, 3662246, 3785000, 3584406, 3589149, 7961130777},
[]int64{1611100800000, 3590194, 3641531, 3340000, 3546823, 8936842292},
[]int64{1611187200000, 3546823, 3560000, 3007100, 3085013, 13500407666},
[]int64{1611273600000, 3085199, 3382653, 2885000, 3294517, 14297168405},
[]int64{1611360000000, 3295000, 3345600, 3139016, 3207800, 6459528768},
[]int64{1611446400000, 3207800, 3307100, 3090000, 3225990, 5797803797},
[]int64{1611532800000, 3225945, 3487500, 3191000, 3225420, 8849922692},
},
}
// */
/* 实盘级Tick
ret := map[string]interface{}{
"detail": map[string]interface{}{
"eid": "Binance",
"symbol": "BTC_USDT",
"alias": "BTCUSDT",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"marginCurrency": "USDT",
"basePrecision": 5,
"quotePrecision": 2,
"minQty": 0.00001,
"maxQty": 9000,
"minNotional": 5,
"maxNotional": 9000000,
"priceTick": 0.01,
"volumeTick": 0.00001,
"marginLevel": 10,
},
"schema": []string{"time", "asks", "bids", "trades", "close", "vol"},
"data": []interface{}{
[]interface{}{1610755200000, []interface{}{[]int64{9531300, 10}}, []interface{}{[]int64{9531300, 10}}, []interface{}{[]int64{1610755200000, 0, 9531300, 10}}, 9497060, 787},
[]interface{}{1610841600000, []interface{}{[]int64{9531300, 15}}, []interface{}{[]int64{9531300, 15}}, []interface{}{[]int64{1610841600000, 0, 9531300, 11}}, 9497061, 789},
},
}
*/
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: 2021-01-16 08:00:00
end: 2021-01-22 00:00:00
period: 1d
basePeriod: 1d
exchanges: [{"eid":"OKX","currency":"BTC_USDT","feeder":"http://120.24.2.20:9090/data"}]
args: [["number",2]]
*/
function main() {
var ticker = exchange.GetTicker()
var records = exchange.GetRecords()
Log(exchange.GetName(), exchange.GetCurrency())
Log(ticker)
Log(records)
}