SPB Git

Repository Public

backtest-report-v2.schema.json 26.7 KB 1,093 lines json

1{2  "$schema": "https://json-schema.org/draft/2020-12/schema",3  "$id": "https://sp-wallet.local/schema/backtest-report-v2.schema.json",4  "title": "SP Wallet V4 backtest report, version 2 (perpetual futures)",5  "description": "Produced by spq.perp_backtest / spq.perp_pipeline (research/). Every key of version 1 (backtest-report.schema.json) is kept with the same meaning; version 2 adds the perpetual-futures metrics, the benchmark perp_long_1x, the exact ledger, the liquidation log, the funding summary and the checks `ledger` and `funding_alignment`. Model and reading guide: docs/v4/quant-perps.md. 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    "schema_version",17    "kind",18    "ledger",19    "liquidations",20    "funding"21  ],22  "properties": {23    "schema_version": {24      "const": 225    },26    "generated_at": {27      "type": "string",28      "format": "date-time"29    },30    "strategy_sha256": {31      "type": "string",32      "pattern": "^[0-9a-f]{64}$"33    },34    "strategy": {35      "type": "object",36      "required": [37        "name",38        "version",39        "meta"40      ],41      "properties": {42        "name": {43          "type": "string"44        },45        "version": {46          "type": "string"47        },48        "meta": {49          "type": "object"50        }51      }52    },53    "config": {54      "type": "object",55      "required": [56        "symbols",57        "interval",58        "start",59        "end",60        "fee_bps",61        "slippage_bps",62        "initial_cash",63        "taker_fee_bps",64        "leverage",65        "max_leverage",66        "max_gross_exposure",67        "maintenance_fraction",68        "liquidation_penalty_bps"69      ],70      "properties": {71        "symbols": {72          "type": "array",73          "items": {74            "type": "string",75            "pattern": "^[A-Za-z0-9]+(\\.SPOT)?$"76          },77          "minItems": 1,78          "uniqueItems": true,79          "description": "perpetuals, and spot legs written <SYMBOL>.SPOT"80        },81        "interval": {82          "type": "string",83          "pattern": "^[0-9]+[mhdw]$"84        },85        "start": {86          "type": "string",87          "format": "date-time",88          "description": "first bar of the data (bar-open time, UTC)"89        },90        "end": {91          "type": "string",92          "format": "date-time",93          "description": "last bar of the data (bar-open time, UTC)"94        },95        "fee_bps": {96          "type": "number",97          "minimum": 098        },99        "slippage_bps": {100          "type": "number",101          "minimum": 0102        },103        "initial_cash": {104          "type": "number",105          "exclusiveMinimum": 0106        },107        "min_order": {108          "type": "number",109          "minimum": 0110        },111        "rebalance_threshold": {112          "type": "number",113          "minimum": 0,114          "maximum": 1115        },116        "decision_every": {117          "type": "integer",118          "minimum": 1119        },120        "params": {121          "type": "object"122        },123        "source": {124          "type": [125            "string",126            "null"127          ]128        },129        "bars": {130          "type": "integer"131        },132        "split_fractions": {133          "type": "array",134          "items": {135            "type": "number"136          },137          "minItems": 3,138          "maxItems": 3139        },140        "venue": {141          "type": [142            "string",143            "null"144          ]145        },146        "taker_fee_bps": {147          "type": "number",148          "minimum": 0149        },150        "maker_fee_bps": {151          "type": "number"152        },153        "liquidity": {154          "enum": [155            "taker",156            "maker"157          ],158          "description": "which fee the fills paid; fee_bps is that fee"159        },160        "leverage": {161          "type": "number",162          "exclusiveMinimum": 0,163          "description": "account leverage setting used for the initial margin (capped per symbol by venue_max_leverage)"164        },165        "max_leverage": {166          "type": "number",167          "exclusiveMinimum": 0,168          "description": "META['max_leverage']: bound of one weight"169        },170        "max_gross_exposure": {171          "type": "number",172          "exclusiveMinimum": 0,173          "description": "META['max_gross_exposure']: bound of the sum of absolute weights"174        },175        "venue_max_leverage": {176          "type": "object",177          "additionalProperties": {178            "type": "number"179          }180        },181        "maintenance_fraction": {182          "type": "object",183          "additionalProperties": {184            "type": "number",185            "minimum": 0,186            "exclusiveMaximum": 1187          }188        },189        "liquidation_penalty_bps": {190          "type": "number",191          "minimum": 0192        },193        "size_decimals": {194          "type": "object",195          "additionalProperties": {196            "type": "integer",197            "minimum": 0198          }199        },200        "spot_fee_bps": {201          "type": "number",202          "minimum": 0203        },204        "spot_slippage_bps": {205          "type": "number",206          "minimum": 0207        },208        "funding_reference_price": {209          "type": "string"210        }211      }212    },213    "splits": {214      "type": "object",215      "required": [216        "train",217        "validation",218        "test"219      ],220      "properties": {221        "train": {222          "type": "array",223          "prefixItems": [224            {225              "type": "string",226              "format": "date-time"227            },228            {229              "type": "string",230              "format": "date-time"231            }232          ],233          "minItems": 2,234          "maxItems": 2,235          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"236        },237        "validation": {238          "type": "array",239          "prefixItems": [240            {241              "type": "string",242              "format": "date-time"243            },244            {245              "type": "string",246              "format": "date-time"247            }248          ],249          "minItems": 2,250          "maxItems": 2,251          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"252        },253        "test": {254          "type": "array",255          "prefixItems": [256            {257              "type": "string",258              "format": "date-time"259            },260            {261              "type": "string",262              "format": "date-time"263            }264          ],265          "minItems": 2,266          "maxItems": 2,267          "description": "[first bar, last bar] (bar-open times, UTC, both inclusive)"268        }269      },270      "additionalProperties": false271    },272    "metrics": {273      "type": "object",274      "required": [275        "train",276        "validation",277        "test"278      ],279      "properties": {280        "train": {281          "$ref": "#/$defs/perp_metrics"282        },283        "validation": {284          "$ref": "#/$defs/perp_metrics"285        },286        "test": {287          "$ref": "#/$defs/perp_metrics"288        }289      },290      "additionalProperties": false291    },292    "benchmarks": {293      "type": "object",294      "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.",295      "required": [296        "buy_and_hold",297        "perp_long_1x"298      ],299      "additionalProperties": {300        "anyOf": [301          {302            "$ref": "#/$defs/perp_metrics"303          },304          {305            "$ref": "#/$defs/metrics"306          }307        ]308      },309      "properties": {310        "buy_and_hold": {311          "anyOf": [312            {313              "$ref": "#/$defs/perp_metrics"314            },315            {316              "$ref": "#/$defs/metrics"317            }318          ],319          "description": "the same assets bought once on the spot market and held (spot engine and costs); the perpetual price without funding when no spot data were supplied (see checks.notes)"320        },321        "perp_long_1x": {322          "$ref": "#/$defs/perp_metrics",323          "description": "perpetuals bought once at 1x, equal weights, held: price PnL and funding, same costs"324        }325      }326    },327    "robustness": {328      "type": "object",329      "required": [330        "walk_forward",331        "bootstrap_sharpe_ci",332        "parameter_sensitivity",333        "trials_tested",334        "deflated_sharpe"335      ],336      "properties": {337        "walk_forward": {338          "type": "array",339          "items": {340            "type": "object",341            "required": [342              "in_sample",343              "out_of_sample",344              "params"345            ]346          }347        },348        "bootstrap_sharpe_ci": {349          "type": "array",350          "prefixItems": [351            {352              "type": [353                "number",354                "null"355              ]356            },357            {358              "type": [359                "number",360                "null"361              ]362            }363          ],364          "minItems": 2,365          "maxItems": 2,366          "description": "[lo, hi] of the annualised Sharpe ratio on the test split"367        },368        "bootstrap": {369          "type": "object"370        },371        "parameter_sensitivity": {372          "type": "array",373          "items": {374            "type": "object",375            "required": [376              "params"377            ]378          }379        },380        "trials_tested": {381          "type": "integer",382          "minimum": 1,383          "description": "number of distinct configurations evaluated before this result (N of the deflated Sharpe ratio)"384        },385        "deflated_sharpe": {386          "type": [387            "number",388            "null"389          ],390          "minimum": 0,391          "maximum": 1,392          "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)"393        },394        "deflated_sharpe_detail": {395          "type": "object"396        },397        "monte_carlo": {398          "type": "object"399        },400        "stress_windows": {401          "type": "array",402          "items": {403            "type": "object",404            "required": [405              "window",406              "benchmark_return",407              "strategy_return"408            ]409          }410        },411        "test_evaluations": {412          "type": "integer",413          "minimum": 1,414          "description": "how many times this strategy name was evaluated on a test split according to the ledger"415        },416        "funding_stress_windows": {417          "type": "array",418          "description": "strategy vs perp_long_1x in the week-long windows of the test split with the highest and the lowest mean funding",419          "items": {420            "type": "object",421            "required": [422              "regime",423              "window",424              "strategy_return"425            ]426          }427        },428        "benchmarks_by_split": {429          "type": "object",430          "description": "total_return / sharpe / max_drawdown of the benchmarks on train and validation"431        }432      }433    },434    "checks": {435      "type": "object",436      "required": [437        "lookahead",438        "data_quality",439        "notes",440        "ledger",441        "funding_alignment"442      ],443      "properties": {444        "lookahead": {445          "enum": [446            "pass",447            "fail"448          ]449        },450        "data_quality": {451          "enum": [452            "pass",453            "fail"454          ]455        },456        "notes": {457          "type": "array",458          "items": {459            "type": "string"460          }461        },462        "data_quality_detail": {463          "type": "object"464        },465        "ledger": {466          "enum": [467            "pass",468            "fail"469          ],470          "description": "pass when, for every run of the report, final equity = initial + realised PnL + funding - fees - slippage + unrealised PnL + debt written off, exactly, both from the running balance and from the trade and funding logs"471        },472        "funding_alignment": {473          "enum": [474            "pass",475            "fail"476          ],477          "description": "pass when the funding column of every perpetual equals the settlement series re-attached by time (settlement at the bar's open hour, none from the future) and settlement instants are on the hour grid"478        },479        "funding_quality_detail": {480          "type": "object"481        },482        "funding_alignment_detail": {}483      }484    },485    "equity_curve": {486      "type": "array",487      "minItems": 2,488      "description": "test split, [bar-open time, equity at that bar's close]",489      "items": {490        "type": "array",491        "prefixItems": [492          {493            "type": "string",494            "format": "date-time"495          },496          {497            "type": "number",498            "minimum": 0499          }500        ],501        "minItems": 2,502        "maxItems": 2503      }504    },505    "kind": {506      "const": "perp"507    },508    "ledger": {509      "type": "object",510      "required": [511        "train",512        "validation",513        "test"514      ],515      "additionalProperties": {516        "type": "object",517        "description": "exact decimal strings (USDC)",518        "required": [519          "initial",520          "realised_pnl",521          "funding",522          "fees",523          "slippage",524          "unrealised_pnl",525          "bad_debt_written_off",526          "final_equity",527          "reconciles"528        ],529        "properties": {530          "initial": {531            "type": "string",532            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"533          },534          "realised_pnl": {535            "type": "string",536            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"537          },538          "funding": {539            "type": "string",540            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"541          },542          "fees": {543            "type": "string",544            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"545          },546          "liquidation_penalties": {547            "type": "string",548            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"549          },550          "slippage": {551            "type": "string",552            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"553          },554          "unrealised_pnl": {555            "type": "string",556            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"557          },558          "bad_debt_written_off": {559            "type": "string",560            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"561          },562          "collateral": {563            "type": "string",564            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"565          },566          "final_equity": {567            "type": "string",568            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"569          },570          "from_logs": {571            "type": "string",572            "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"573          },574          "reconciles": {575            "type": "boolean"576          }577        }578      }579    },580    "liquidations": {581      "type": "object",582      "required": [583        "train",584        "validation",585        "test"586      ],587      "additionalProperties": {588        "type": "array",589        "items": {590          "type": "object",591          "required": [592            "ts",593            "reason",594            "positions"595          ]596        }597      }598    },599    "funding": {600      "type": "object",601      "description": "per split and perpetual: funding rates seen by the run",602      "required": [603        "train",604        "validation",605        "test"606      ]607    }608  },609  "$defs": {610    "metrics": {611      "type": "object",612      "description": "Metrics of one backtest window. Ratios that are undefined (no variance, no drawdown, no closed lot, no losing lot) are null.",613      "required": [614        "total_return",615        "cagr",616        "volatility",617        "sharpe",618        "sortino",619        "max_drawdown",620        "calmar",621        "turnover",622        "trades",623        "win_rate",624        "profit_factor",625        "fees_paid",626        "exposure",627        "slippage_paid",628        "returns"629      ],630      "properties": {631        "total_return": {632          "type": [633            "number",634            "null"635          ]636        },637        "cagr": {638          "type": [639            "number",640            "null"641          ]642        },643        "volatility": {644          "type": [645            "number",646            "null"647          ],648          "minimum": 0,649          "description": "annualised with the bar interval, 24/7 market"650        },651        "sharpe": {652          "type": [653            "number",654            "null"655          ]656        },657        "sortino": {658          "type": [659            "number",660            "null"661          ]662        },663        "max_drawdown": {664          "type": [665            "number",666            "null"667          ],668          "minimum": 0,669          "maximum": 1,670          "description": "positive fraction: 0.35 means -35 %"671        },672        "calmar": {673          "type": [674            "number",675            "null"676          ]677        },678        "turnover": {679          "type": [680            "number",681            "null"682          ],683          "minimum": 0,684          "description": "traded notional / average equity over the window"685        },686        "turnover_annual": {687          "type": [688            "number",689            "null"690          ],691          "minimum": 0692        },693        "trades": {694          "type": "integer",695          "minimum": 0,696          "description": "number of fills"697        },698        "closed_lots": {699          "type": "integer",700          "minimum": 0701        },702        "win_rate": {703          "type": [704            "number",705            "null"706          ],707          "minimum": 0,708          "maximum": 1709        },710        "profit_factor": {711          "type": [712            "number",713            "null"714          ],715          "minimum": 0716        },717        "fees_paid": {718          "type": [719            "number",720            "null"721          ],722          "minimum": 0723        },724        "slippage_paid": {725          "type": [726            "number",727            "null"728          ],729          "minimum": 0730        },731        "exposure": {732          "type": [733            "number",734            "null"735          ],736          "minimum": 0,737          "maximum": 1.000001,738          "description": "average invested fraction of equity"739        },740        "bars": {741          "type": "integer",742          "minimum": 2743        },744        "final_equity": {745          "type": [746            "number",747            "null"748          ]749        },750        "returns": {751          "type": "object",752          "description": "per-bar return distribution",753          "required": [754            "n"755          ],756          "properties": {757            "n": {758              "type": "integer"759            }760          },761          "additionalProperties": {762            "type": [763              "number",764              "null"765            ]766          }767        }768      },769      "additionalProperties": false770    },771    "perp_metrics": {772      "type": "object",773      "description": "Metrics of one backtest window. Ratios that are undefined (no variance, no drawdown, no closed lot, no losing lot) are null.",774      "required": [775        "total_return",776        "cagr",777        "volatility",778        "sharpe",779        "sortino",780        "max_drawdown",781        "calmar",782        "turnover",783        "trades",784        "win_rate",785        "profit_factor",786        "fees_paid",787        "exposure",788        "slippage_paid",789        "returns",790        "realised_pnl",791        "funding_pnl",792        "liquidation_penalties",793        "long_exposure",794        "short_exposure",795        "gross_leverage_mean",796        "gross_leverage_max",797        "net_leverage_mean",798        "net_leverage_max",799        "net_leverage_min",800        "time_in_market",801        "avg_holding_bars",802        "avg_holding_hours",803        "liquidations",804        "wiped_out",805        "margin_utilisation_mean",806        "margin_utilisation_max",807        "worst_intrabar_drawdown",808        "orders_cut",809        "orders_refused",810        "funding_payments",811        "funding_missing"812      ],813      "properties": {814        "total_return": {815          "type": [816            "number",817            "null"818          ]819        },820        "cagr": {821          "type": [822            "number",823            "null"824          ]825        },826        "volatility": {827          "type": [828            "number",829            "null"830          ],831          "minimum": 0,832          "description": "annualised with the bar interval, 24/7 market"833        },834        "sharpe": {835          "type": [836            "number",837            "null"838          ]839        },840        "sortino": {841          "type": [842            "number",843            "null"844          ]845        },846        "max_drawdown": {847          "type": [848            "number",849            "null"850          ],851          "minimum": 0,852          "maximum": 1,853          "description": "positive fraction: 0.35 means -35 %"854        },855        "calmar": {856          "type": [857            "number",858            "null"859          ]860        },861        "turnover": {862          "type": [863            "number",864            "null"865          ],866          "minimum": 0,867          "description": "traded notional / average equity over the window"868        },869        "turnover_annual": {870          "type": [871            "number",872            "null"873          ],874          "minimum": 0875        },876        "trades": {877          "type": "integer",878          "minimum": 0,879          "description": "number of fills"880        },881        "closed_lots": {882          "type": "integer",883          "minimum": 0884        },885        "win_rate": {886          "type": [887            "number",888            "null"889          ],890          "minimum": 0,891          "maximum": 1892        },893        "profit_factor": {894          "type": [895            "number",896            "null"897          ],898          "minimum": 0899        },900        "fees_paid": {901          "type": [902            "number",903            "null"904          ],905          "minimum": 0,906          "description": "USD, trading fees + liquidation penalties"907        },908        "slippage_paid": {909          "type": [910            "number",911            "null"912          ],913          "minimum": 0914        },915        "exposure": {916          "type": [917            "number",918            "null"919          ],920          "minimum": 0,921          "description": "mean gross exposure / equity (for a long-only spot run: the invested fraction)"922        },923        "bars": {924          "type": "integer",925          "minimum": 2926        },927        "final_equity": {928          "type": [929            "number",930            "null"931          ]932        },933        "returns": {934          "type": "object",935          "description": "per-bar return distribution",936          "required": [937            "n"938          ],939          "properties": {940            "n": {941              "type": "integer"942            }943          },944          "additionalProperties": {945            "type": [946              "number",947              "null"948            ]949          }950        },951        "realised_pnl": {952          "type": [953            "number",954            "null"955          ],956          "description": "USD, sum of the realised PnL of closing fills (fees excluded)"957        },958        "funding_pnl": {959          "type": [960            "number",961            "null"962          ],963          "description": "USD, sum of funding payments; negative = paid"964        },965        "liquidation_penalties": {966          "type": [967            "number",968            "null"969          ],970          "description": "USD, part of fees_paid"971        },972        "long_exposure": {973          "type": [974            "number",975            "null"976          ],977          "description": "mean long notional / equity"978        },979        "short_exposure": {980          "type": [981            "number",982            "null"983          ],984          "description": "mean short notional / equity (positive)"985        },986        "gross_leverage_mean": {987          "type": [988            "number",989            "null"990          ],991          "description": "mean (long + short notional) / equity"992        },993        "gross_leverage_max": {994          "type": [995            "number",996            "null"997          ],998          "description": "maximum of the same at bar closes"999        },1000        "net_leverage_mean": {1001          "type": [1002            "number",1003            "null"1004          ],1005          "description": "mean (long - short notional) / equity"1006        },1007        "net_leverage_max": {1008          "type": [1009            "number",1010            "null"1011          ],1012          "description": "largest net long"1013        },1014        "net_leverage_min": {1015          "type": [1016            "number",1017            "null"1018          ],1019          "description": "largest net short (negative)"1020        },1021        "time_in_market": {1022          "type": [1023            "number",1024            "null"1025          ],1026          "description": "share of bars ending with a position"1027        },1028        "avg_holding_bars": {1029          "type": [1030            "number",1031            "null"1032          ],1033          "description": "mean run of bars with a same-sign position in one symbol"1034        },1035        "avg_holding_hours": {1036          "type": [1037            "number",1038            "null"1039          ],1040          "description": "same in hours"1041        },1042        "liquidations": {1043          "type": "integer",1044          "minimum": 0,1045          "description": "account liquidations (each closes every perpetual position)"1046        },1047        "wiped_out": {1048          "type": "boolean",1049          "description": "equity reached zero; the run stopped there"1050        },1051        "margin_utilisation_mean": {1052          "type": [1053            "number",1054            "null"1055          ],1056          "description": "initial margin in use / margin equity, bars with a perpetual position"1057        },1058        "margin_utilisation_max": {1059          "type": [1060            "number",1061            "null"1062          ],1063          "description": "maximum of the same"1064        },1065        "worst_intrabar_drawdown": {1066          "type": [1067            "number",1068            "null"1069          ],1070          "description": "positive fraction; uses each bar's adverse extreme against the previous closing peak"1071        },1072        "orders_cut": {1073          "type": "integer",1074          "minimum": 01075        },1076        "orders_refused": {1077          "type": "integer",1078          "minimum": 01079        },1080        "funding_payments": {1081          "type": "integer",1082          "minimum": 01083        },1084        "funding_missing": {1085          "type": "integer",1086          "minimum": 01087        }1088      },1089      "additionalProperties": false1090    }1091  }1092}1093
Files main
Menu

Theme