Appearance
Backtest
Loads historical candles, runs a script over the window, and returns candles, per-bar chart outputs, and strategy reports when applicable.
Service: dxscript.backtesting.v1.BacktestingService
Method: backtest
Interaction: request / response
HTTP
http
POST /dxscript.backtesting.v1.backtestingservice/backtest
Content-Type: application/jsonRequest
| Field | Type | Required | Description |
|---|---|---|---|
lang | string | yes | Must be dxscript-js |
content | string | yes | Full script source |
symbol | string | yes | Candle symbol (e.g. AAPL{=d}) |
fromTime | string | yes | Range start as RFC 3339 timestamp |
toTime | string | yes | Range end as RFC 3339 timestamp |
fromTime must be before or equal to toTime. Invalid symbols return a validation error without loading candles.
Examples
Strategy backtest (success)
bash
curl -sS -X POST 'https://dxlink-dxscript-http-demo.dxkube.com/dxscript.backtesting.v1.backtestingservice/backtest' \
-H 'Content-Type: application/json' \
-d '{
"lang": "dxscript-js",
"content": "strategy({ initialCapital: 10000, title: \"MA Crossover\" });\nconst fast = input.double(\"Fast\", 10);\nconst slow = input.double(\"Slow\", 20);\nfunction onTick() {\n const f = ta.sma(close, fast);\n const s = ta.sma(close, slow);\n if (bar.isConfirmed()) {\n if (ta.crossover(f, s)) strategy.entry(\"long\", strategy.LONG);\n if (ta.crossunder(f, s)) strategy.close(\"long\");\n }\n spline(f, { title: \"Fast\" });\n spline(s, { title: \"Slow\" });\n}",
"symbol": "AAPL{=d}",
"fromTime": "2024-01-01T00:00:00Z",
"toTime": "2024-03-01T00:00:00Z"
}'Request body:
json
{
"lang": "dxscript-js",
"content": "strategy({ initialCapital: 10000, title: \"MA Crossover\" });\nconst fast = input.double(\"Fast\", 10);\nconst slow = input.double(\"Slow\", 20);\nfunction onTick() {\n const f = ta.sma(close, fast);\n const s = ta.sma(close, slow);\n if (bar.isConfirmed()) {\n if (ta.crossover(f, s)) strategy.entry(\"long\", strategy.LONG);\n if (ta.crossunder(f, s)) strategy.close(\"long\");\n }\n spline(f, { title: \"Fast\" });\n spline(s, { title: \"Slow\" });\n}",
"symbol": "AAPL{=d}",
"fromTime": "2024-01-01T00:00:00Z",
"toTime": "2024-03-01T00:00:00Z"
}Response 200 — error is absent (truncated; this run returned 42 daily bars and no fills, so strategyTradeReport and strategyFillReport are omitted):
json
{
"meta": {
"title": "MA Crossover"
},
"candles": [
{
"eventSymbol": "AAPL{=d}",
"eventTime": "0",
"eventFlags": 0,
"index": "7319283979360665600",
"time": "1704153600000",
"sequence": 0,
"count": "1008888",
"open": 187.15,
"high": 188.44,
"low": 183.885,
"close": 185.64,
"impVolatility": 0.2491,
"askVolume": 50986581.0,
"bidVolume": 31506006.0,
"openInterest": "NaN",
"source": "DEFAULT",
"volume": 82488674.0,
"vwap": 185.893310807251
},
{
"eventSymbol": "AAPL{=d}",
"eventTime": "0",
"eventFlags": 0,
"index": "7319655064535040000",
"time": "1704240000000",
"sequence": 0,
"count": "656859",
"open": 184.22,
"high": 185.88,
"low": 183.43,
"close": 184.25,
"impVolatility": 0.2515,
"askVolume": 33221869.0,
"bidVolume": 25193853.0,
"openInterest": "NaN",
"source": "DEFAULT",
"volume": 58414460.0,
"vwap": 184.3191143024005
}
],
"calculationResult": {
"spline": {
"0": {
"knots": [
{ "value": "NaN", "style": "LINE", "offset": 0, "title": "Fast", "overlay": true },
{ "value": "NaN" },
{ "value": "NaN" },
{ "value": "NaN" }
]
},
"1": {
"knots": [
{ "value": "NaN", "style": "LINE", "offset": 0, "title": "Slow", "overlay": true },
{ "value": "NaN" },
{ "value": "NaN" },
{ "value": "NaN" }
]
}
}
},
"strategyAnalytics": {
"equitySeries": [10000.0, 10000.0, 10000.0],
"barCloseSeries": [185.64, 184.25, 181.91],
"performance": {
"initialCapital": 10000.0,
"finalEquity": 10000.0,
"buyHoldReturnPercent": -3.221288515406162,
"strategyOutperformancePercent": 3.221288515406162
}
}
}Notes on this response:
candlesuse the full dxFeed candle shape.timeis epoch milliseconds as a string;openInterestmay serialize as the string"NaN".calculationResult.splineis keyed by layer id ("0","1", …), not spline title. Eachknotsarray has one entry per loaded bar; static metadata appears on the first knot only.calculationResult.outputchannels use{ "values": [...] }with one entry per loaded bar. Warmup bars use the non-finite string"NaN", notnull.- Leading
"NaN"knots are normal while moving averages warm up. strategyTradeReportandstrategyFillReportappear once the strategy fills an order; a position still open at the end of the window is a trade row with"open": true.performancemay include only a subset of summary fields when others are not applicable.
Script error after candles are loaded
When execution fails after compilation, candles is still returned:
bash
curl -sS -X POST 'https://dxlink-dxscript-http-demo.dxkube.com/dxscript.backtesting.v1.backtestingservice/backtest' \
-H 'Content-Type: application/json' \
-d '{
"lang": "dxscript-js",
"content": "strategy({ title: \"Broken Strategy\" });\nfunction onTick() {\n missingHelper();\n}",
"symbol": "AAPL{=d}",
"fromTime": "2024-01-01T00:00:00Z",
"toTime": "2024-01-02T00:00:00Z"
}'Response 200:
json
{
"candles": [
{
"eventSymbol": "AAPL{=d}",
"eventTime": "0",
"eventFlags": 0,
"index": "7319283979360665600",
"time": "1704153600000",
"sequence": 0,
"count": "1008888",
"open": 187.15,
"high": 188.44,
"low": 183.885,
"close": 185.64,
"impVolatility": 0.2491,
"askVolume": 50986581.0,
"bidVolume": 31506006.0,
"openInterest": "NaN",
"source": "DEFAULT",
"volume": 82488674.0,
"vwap": 185.893310807251
}
],
"error": {
"id": "9e5e5647-fc5a-45ce-bc42-fb3f2a2bcd4f",
"type": "RUNTIME",
"scriptName": "backtest",
"startLine": 3,
"startColumn": 3,
"endLine": 3,
"endColumn": 15,
"message": "missingHelper is not defined",
"scriptStack": [
{ "functionName": "onTick", "line": 3, "column": 3 }
]
}
}Candle fetch failure
When the candle provider throws (timeout, connectivity, or upstream failure), candles is empty and error carries the provider exception:
json
{
"candles": [],
"error": {
"type": "TimeoutException",
"scriptName": "",
"startLine": -1,
"startColumn": -1,
"endLine": -1,
"endColumn": -1,
"message": "Candle feed fetch timed out after PT2M",
"scriptStack": []
}
}error.type is the Java exception simple name; id is omitted when empty. Some demo feeds return a placeholder candle for unknown symbols instead of raising this error.
Response fields
| Field | Type | Description |
|---|---|---|
candles | array | Loaded candles in full dxFeed market-data format |
calculationResult | object | Per-bar chart outputs for the full window; omitted channels are absent |
strategyTradeReport | object | Closed/open trades; omitted when there are no trades |
strategyFillReport | object | Entry/exit fills; omitted when there are no fills |
strategyOrderReport | object | Resting and refused orders with their type and status; omitted when no order rested or was refused |
strategyAnalytics | object | Equity curve and performance summary for strategy scripts |
meta | object | title, shortTitle when declared |
error | object | Structured script or fetch error; present on failure only |
calculationResult
Unlike validation, every channel contains one value per loaded bar (same length and order as candles):
| Channel | Map key | Value shape |
|---|---|---|
output | channel name | { values: [...] } — one entry per bar; numbers or non-finite strings ("NaN", "Infinity", "-Infinity"), never null |
spline | layer id ("0", "1", …) | { knots: [...] } — one knot per bar |
backgroundColor | layer key | { values: [...] } |
barColor | layer key | { values: [...] } |
shape | series key | { points: [...] } |
Spline knots follow the same metadata conventions as the Validate response, extended to every bar. Static fields (title, style, offset, overlay) appear on the first knot; later knots usually carry only value.
strategyTradeReport.trades[]
| Field | Description |
|---|---|
tradeNumber | Sequential trade id |
direction | LONG or SHORT |
entrySignal, exitSignal | Signal names from strategy.entry() / strategy.close() |
entryBarIndex, exitBarIndex | Bar indices in the loaded window |
entryTimeMillis, exitTimeMillis | Fill timestamps |
entryPrice, exitPrice | Fill prices |
size | Position size |
netPnl, cumulativePnl | Trade and running PnL |
maxRunup, maxDrawdown | Intrabar excursion while trade was open |
open | true when the trade has no exit yet |
entrySide, exitSide | BUY or SELL |
strategyAnalytics
| Field | Description |
|---|---|
equitySeries | Account equity per bar |
barCloseSeries | Underlying close prices for comparison |
totalCommissionPaid | Cumulative commission |
performance | Summary metrics (see below) |
performance may include initialCapital, finalEquity, netProfit, profitFactor, totalClosedTrades, winningTrades, losingTrades, percentProfitable, maxEquityDrawdown, sharpeRatio, sortinoRatio, buyHoldReturnPercent, strategyReturnPercent, strategyOutperformancePercent, and related fields. Only applicable fields are serialized.
WebSocket RPC
Call backtest on service dxscript.backtesting.v1.BacktestingService through the dxLink WebSocket session. Request and response use the BacktestRequest / BacktestResponse protobuf messages.
See also
- Backtesting service
- Strategy — order simulation and report semantics