{"trades":{"endpoint":"POST /v1/validate/trades","body":{"description":"Tier 1 - a list of closed-trade returns, nothing else required.","properties":{"returns_r":{"description":"Per-trade result in R (multiples of the risk taken on that trade). A trade stopped out at its initial stop is -1.0. Order must be chronological.","items":{"type":"number"},"minItems":30,"title":"Returns R","type":"array"},"n_trials_declared":{"default":1,"description":"How many strategy variants you tried in total before settling on this one - every parameter set, symbol and timeframe, including the ones you discarded. This is the single most important number you can give us, and the one people understate.","minimum":1,"title":"N Trials Declared","type":"integer"},"trial_sharpes":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"default":null,"description":"Optional: the per-trade Sharpe of every variant you tried. Supplying these makes the multiple-testing correction exact instead of approximated.","title":"Trial Sharpes"},"cost_per_trade_r":{"default":0.0,"description":"Optional: additional round-trip cost in R to subtract from every trade before testing, if your backtest was run gross of fees and slippage.","minimum":0.0,"title":"Cost Per Trade R","type":"number"}},"required":["returns_r"],"title":"TradesRequest","type":"object"},"example":{"returns_r":[-1.0,2.3,-1.0,-1.0,0.8,1.9],"n_trials_declared":12,"cost_per_trade_r":0.02},"note":"returns_r must be chronological and in R-multiples. Minimum 30 trades, though a verdict below ~200 will usually be UNPROVEN on sample size alone."},"filter":{"endpoint":"POST /v1/validate/filter","body":{"description":"Tier 2 - candidate trades with the features known at decision time.","properties":{"feature_names":{"items":{"type":"string"},"minItems":1,"title":"Feature Names","type":"array"},"features":{"description":"One row per candidate trade, in chronological order. Every value must have been computable strictly BEFORE that trade's entry - this is the assumption the whole audit rests on, and the one we can only partly check.","items":{"items":{"type":"number"},"type":"array"},"minItems":120,"title":"Features","type":"array"},"returns_r":{"description":"Outcome of each candidate trade in R, same order as `features`. Include the trades your filter rejected: without them there is no baseline to measure lift against, and lift is the entire question.","items":{"type":"number"},"minItems":120,"title":"Returns R","type":"array"},"gross_returns_r":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"default":null,"description":"Optional but strongly recommended: the same trades BEFORE fees and slippage. Any feature that is part of how `returns_r` is computed - a fee column, a slippage estimate, anything subtracted to get net - will correlate with it by arithmetic alone. Supplying gross lets us re-measure against a target the feature is not part of, which is the only way to tell a real effect from bookkeeping.","title":"Gross Returns R"},"entry_ms":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"default":null,"description":"Optional entry timestamps (epoch ms). Supplying these lets us detect overlapping trades, which silently invalidate walk-forward testing.","title":"Entry Ms"},"exit_ms":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"default":null,"description":"Optional exit timestamps (epoch ms).","title":"Exit Ms"},"claimed_lift_r":{"anyOf":[{"type":"number"},{"type":"null"}],"default":null,"description":"Optional: the out-of-sample edge your own backtest reported for the filtered subset, in R above the unfiltered baseline. We report the gap between your number and our strict replay.","title":"Claimed Lift R"},"selection_threshold_r":{"default":0.1,"description":"Predicted-R cutoff above which a trade is selected. Higher means a more selective filter.","title":"Selection Threshold R","type":"number"},"permutations":{"default":50,"description":"Permutations used to build the chance distribution. The p-value cannot resolve below 1/(permutations+1).","minimum":20,"title":"Permutations","type":"integer"}},"required":["feature_names","features","returns_r"],"title":"FilterRequest","type":"object"},"example":{"feature_names":["atr_pct","trend_eff"],"features":[[1.2,0.4],[0.9,0.7]],"returns_r":[-1.0,2.1],"gross_returns_r":[-0.87,2.24],"claimed_lift_r":0.29,"selection_threshold_r":0.1},"note":"include the candidate trades your filter REJECTED. Without them there is no baseline, and lift over baseline is the only statistic that means anything here."},"verdicts":{"PASS":"survived every applicable check","WEAK":"probably real, but small or fragile","REVIEW":"a heuristic flagged something we cannot settle from the numbers - confirm the named item and the verdict resolves. Not a finding of wrongdoing","UNPROVEN":"not distinguishable from luck. This is NOT a finding that the strategy is worthless - only that this evidence does not support the claim","FAIL":"actively contradicted by the data","VOID":"our own harness failed its self-check; not billable"}}