Type/to search
Getting Started
Platform Basics
Writing Strategies
Development Tools
Backtesting System
Overview and Starting a Backtest
Backtest Modes and Order Matching
Backtest Configuration and Saving
Supported Languages and Exchanges
Reading Backtest Results
Parameter Optimization
Custom Data Source
Data Format
Custom Data Source Example
Local Backtesting Engine
Backtest Page Shortcuts
Advanced Topics
Data and Research
Extended API Interface

A minimal custom data source service written in Go, and a test strategy to check it. Steps:

  1. Deploy the service below on a server reachable from the public internet; the data source URL is then http://<server>:9090/data (replace <server> with the server's public IP or domain name).
  2. In the backtest configuration, set the exchange's data source (feeder) to that URL and backtest the test strategy below.

The service:

mylang
package main import ( "fmt" "net/http" "encoding/json" ) func Handle (w http.ResponseWriter, r *http.Request) { // e.g. set on backtest DataSource: 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 // request: GET 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] ] } */ // /* Simulation-level 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{}{ // 1610755200000: 2021-01-16 08:00:00 []int64{1610755200000, 3673743, 3795000, 3535780, 3599498, 8634843151}, // 1610841600000: 2021-01-17 08:00:00 []int64{1610841600000, 3599498, 3685250, 3385000, 3582861, 8015772738}, []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}, }, } // */ /* Live trading-level 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) }

Test strategy (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://<server>:9090/data"}] args: [["number",2]] */ function main() { var ticker = exchange.GetTicker() var records = exchange.GetRecords() Log(exchange.GetName(), exchange.GetCurrency()) Log(ticker) Log(records) }