SPB Git

Repository Public

backtest-report.schema.json 12.0 KB 526 lines json

1{2  "$schema": "https://json-schema.org/draft/2020-12/schema",3  "$id": "https://sp-wallet.local/schema/backtest-report.schema.json",4  "title": "SP Wallet V3 backtest report",5  "description": "Produced by spq.backtest (research/), stored by the API. Follows docs/v3/ARCHITECTURE.md 'Backtest report'; keys beyond that document are additions of the lab. A report states what was measured, on which data, with which costs; it never says a strategy is profitable.",6  "type": "object",7  "required": [8    "strategy_sha256",9    "config",10    "splits",11    "metrics",12    "benchmarks",13    "robustness",14    "checks",15    "equity_curve"16  ],17  "properties": {18    "schema_version": {19      "const": 120    },21    "generated_at": {22      "type": "string",23      "format": "date-time"24    },25    "strategy_sha256": {26      "type": "string",27      "pattern": "^[0-9a-f]{64}$"28    },29    "strategy": {30      "type": "object",31      "required": [32        "name",33        "version",34        "meta"35      ],36      "properties": {37        "name": {38          "type": "string"39        },40        "version": {41          "type": "string"42        },43        "meta": {44          "type": "object"45        }46      }47    },48    "config": {49      "type": "object",50      "required": [51        "symbols",52        "interval",53        "start",54        "end",55        "fee_bps",56        "slippage_bps",57        "initial_cash"58      ],59      "properties": {60        "symbols": {61          "type": "array",62          "items": {63            "type": "string",64            "pattern": "^[A-Z0-9]+$"65          },66          "minItems": 1,67          "uniqueItems": true68        },69        "interval": {70          "type": "string",71          "pattern": "^[0-9]+[mhdw]$"72        },73        "start": {74          "type": "string",75          "format": "date-time",76          "description": "first bar of the data (bar-open time, UTC)"77        },78        "end": {79          "type": "string",80          "format": "date-time",81          "description": "last bar of the data (bar-open time, UTC)"82        },83        "fee_bps": {84          "type": "number",85          "minimum": 086        },87        "slippage_bps": {88          "type": "number",89          "minimum": 090        },91        "initial_cash": {92          "type": "number",93          "exclusiveMinimum": 094        },95        "min_order": {96          "type": "number",97          "minimum": 098        },99        "rebalance_threshold": {100          "type": "number",101          "minimum": 0,102          "maximum": 1103        },104        "decision_every": {105          "type": "integer",106          "minimum": 1107        },108        "params": {109          "type": "object"110        },111        "source": {112          "type": [113            "string",114            "null"115          ]116        },117        "bars": {118          "type": "integer"119        },120        "split_fractions": {121          "type": "array",122          "items": {123            "type": "number"124          },125          "minItems": 3,126          "maxItems": 3127        }128      }129    },130    "splits": {131      "type": "object",132      "required": [133        "train",134        "validation",135        "test"136      ],137      "properties": {138        "train": {139          "type": "array",140          "prefixItems": [141            {142              "type": "string",143              "format": "date-time"144            },145            {146              "type": "string",147              "format": "date-time"148            }149          ],150          "minItems": 2,151          "maxItems": 2,152          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"153        },154        "validation": {155          "type": "array",156          "prefixItems": [157            {158              "type": "string",159              "format": "date-time"160            },161            {162              "type": "string",163              "format": "date-time"164            }165          ],166          "minItems": 2,167          "maxItems": 2,168          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"169        },170        "test": {171          "type": "array",172          "prefixItems": [173            {174              "type": "string",175              "format": "date-time"176            },177            {178              "type": "string",179              "format": "date-time"180            }181          ],182          "minItems": 2,183          "maxItems": 2,184          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"185        }186      },187      "additionalProperties": false188    },189    "metrics": {190      "type": "object",191      "required": [192        "train",193        "validation",194        "test"195      ],196      "properties": {197        "train": {198          "$ref": "#/$defs/metrics"199        },200        "validation": {201          "$ref": "#/$defs/metrics"202        },203        "test": {204          "$ref": "#/$defs/metrics"205        }206      },207      "additionalProperties": false208    },209    "benchmarks": {210      "type": "object",211      "description": "Same metrics on the TEST split. buy_and_hold: equal weights bought once, never rebalanced (the single asset when there is one symbol); equal_weight: rebalanced; buy_and_hold_<SYM>: one asset.",212      "required": [213        "buy_and_hold"214      ],215      "additionalProperties": {216        "$ref": "#/$defs/metrics"217      }218    },219    "robustness": {220      "type": "object",221      "required": [222        "walk_forward",223        "bootstrap_sharpe_ci",224        "parameter_sensitivity",225        "trials_tested",226        "deflated_sharpe"227      ],228      "properties": {229        "walk_forward": {230          "type": "array",231          "items": {232            "type": "object",233            "required": [234              "in_sample",235              "out_of_sample",236              "params"237            ]238          }239        },240        "bootstrap_sharpe_ci": {241          "type": "array",242          "prefixItems": [243            {244              "type": [245                "number",246                "null"247              ]248            },249            {250              "type": [251                "number",252                "null"253              ]254            }255          ],256          "minItems": 2,257          "maxItems": 2,258          "description": "[lo, hi] of the annualised Sharpe ratio on the test split"259        },260        "bootstrap": {261          "type": "object"262        },263        "parameter_sensitivity": {264          "type": "array",265          "items": {266            "type": "object",267            "required": [268              "params"269            ]270          }271        },272        "trials_tested": {273          "type": "integer",274          "minimum": 1,275          "description": "number of distinct configurations evaluated before this result (N of the deflated Sharpe ratio)"276        },277        "deflated_sharpe": {278          "type": [279            "number",280            "null"281          ],282          "minimum": 0,283          "maximum": 1,284          "description": "Bailey & Lopez de Prado (2014): probability that the true Sharpe ratio is positive given trials_tested trials; null when undefined (e.g. no variance)"285        },286        "deflated_sharpe_detail": {287          "type": "object"288        },289        "monte_carlo": {290          "type": "object"291        },292        "stress_windows": {293          "type": "array",294          "items": {295            "type": "object",296            "required": [297              "window",298              "benchmark_return",299              "strategy_return"300            ]301          }302        },303        "test_evaluations": {304          "type": "integer",305          "minimum": 1,306          "description": "how many times this strategy name was evaluated on a test split according to the ledger"307        }308      }309    },310    "checks": {311      "type": "object",312      "required": [313        "lookahead",314        "data_quality",315        "notes"316      ],317      "properties": {318        "lookahead": {319          "enum": [320            "pass",321            "fail"322          ]323        },324        "data_quality": {325          "enum": [326            "pass",327            "fail"328          ]329        },330        "notes": {331          "type": "array",332          "items": {333            "type": "string"334          }335        },336        "data_quality_detail": {337          "type": "object"338        }339      }340    },341    "equity_curve": {342      "type": "array",343      "minItems": 2,344      "description": "test split, [bar-open time, equity at that bar's close]",345      "items": {346        "type": "array",347        "prefixItems": [348          {349            "type": "string",350            "format": "date-time"351          },352          {353            "type": "number",354            "minimum": 0355          }356        ],357        "minItems": 2,358        "maxItems": 2359      }360    }361  },362  "$defs": {363    "metrics": {364      "type": "object",365      "description": "Metrics of one backtest window. Ratios that are undefined (no variance, no drawdown, no closed lot, no losing lot) are null.",366      "required": [367        "total_return",368        "cagr",369        "volatility",370        "sharpe",371        "sortino",372        "max_drawdown",373        "calmar",374        "turnover",375        "trades",376        "win_rate",377        "profit_factor",378        "fees_paid",379        "exposure",380        "slippage_paid",381        "returns"382      ],383      "properties": {384        "total_return": {385          "type": [386            "number",387            "null"388          ]389        },390        "cagr": {391          "type": [392            "number",393            "null"394          ]395        },396        "volatility": {397          "type": [398            "number",399            "null"400          ],401          "minimum": 0,402          "description": "annualised with the bar interval, 24/7 market"403        },404        "sharpe": {405          "type": [406            "number",407            "null"408          ]409        },410        "sortino": {411          "type": [412            "number",413            "null"414          ]415        },416        "max_drawdown": {417          "type": [418            "number",419            "null"420          ],421          "minimum": 0,422          "maximum": 1,423          "description": "positive fraction: 0.35 means -35 %"424        },425        "calmar": {426          "type": [427            "number",428            "null"429          ]430        },431        "turnover": {432          "type": [433            "number",434            "null"435          ],436          "minimum": 0,437          "description": "traded notional / average equity over the window"438        },439        "turnover_annual": {440          "type": [441            "number",442            "null"443          ],444          "minimum": 0445        },446        "trades": {447          "type": "integer",448          "minimum": 0,449          "description": "number of fills"450        },451        "closed_lots": {452          "type": "integer",453          "minimum": 0454        },455        "win_rate": {456          "type": [457            "number",458            "null"459          ],460          "minimum": 0,461          "maximum": 1462        },463        "profit_factor": {464          "type": [465            "number",466            "null"467          ],468          "minimum": 0469        },470        "fees_paid": {471          "type": [472            "number",473            "null"474          ],475          "minimum": 0476        },477        "slippage_paid": {478          "type": [479            "number",480            "null"481          ],482          "minimum": 0483        },484        "exposure": {485          "type": [486            "number",487            "null"488          ],489          "minimum": 0,490          "maximum": 1.000001,491          "description": "average invested fraction of equity"492        },493        "bars": {494          "type": "integer",495          "minimum": 2496        },497        "final_equity": {498          "type": [499            "number",500            "null"501          ]502        },503        "returns": {504          "type": "object",505          "description": "per-bar return distribution",506          "required": [507            "n"508          ],509          "properties": {510            "n": {511              "type": "integer"512            }513          },514          "additionalProperties": {515            "type": [516              "number",517              "null"518            ]519          }520        }521      },522      "additionalProperties": false523    }524  }525}526
Files main
Menu

Theme