# Tool reference All 39 tools exposed by the quant-research MCP server at https://quant-mcp.avasis.ai/mcp, generated from the live tools/list response. ## data_ingest Backfill OHLCV into the catalog. Asynchronous — returns a job_id. The worker handles Coinbase's 300-candle-per-request limit by chunking with backoff. For 1-minute history prefer a bulk CSV; the API is for recent top-up, not for pulling a year 300 bars at a time. | Parameter | Type | Required | Notes | |---|---|---|---| | `symbol` | string | yes | e.g. BTC-USD | | `timeframe` | string | yes | 1m, 5m, 15m, 1h, 6h, 1d | | `start` | string | yes | ISO8601 UTC, inclusive | | `end` | string | yes | ISO8601 UTC, exclusive | | `source` | string | no | Default: `"coinbase"` | | `path` | string | no | server-side CSV path when source is csv_upload/cdd | | `venue` | string | no | Default: `"coinbase"` | | `client_request_id` | string | no | | ## data_catalog List datasets with summary stats. Never returns bars. | Parameter | Type | Required | Notes | |---|---|---|---| | `symbol` | string | no | | ## data_quality_report Gap accounting, OHLC structural violations and per-source lineage. The checks are cheap and catch vendor corruption immediately: high below low, close outside the bar's range, duplicated or non-positive prices. | Parameter | Type | Required | Notes | |---|---|---|---| | `dataset_id` | string | yes | | ## data_gap_policy_set Choose how gaps are handled in backtests on this dataset. There is deliberately no forward_fill. Forward-fill fabricates flat bars, suppresses realised volatility and triggers phantom signals. 'skip' used to zero the return of the interval spanning a hole. That was wrong in the direction that flatters a strategy: a position already on at the pre-gap open cannot be flattened inside the outage without lookahead, so the gap move IS earned by whatever was held, and zeroing it deleted real drawdowns from the equity curve. With opens [100, 100, 70, 71] a constant long booked 0% across the hole instead of -30%. That interval is now priced like any other under both policies, which leaves 'skip' with no effect on P&L. Both settings still record gap_count in the quality report and mark gap bars untradable. The option is kept because splits freeze the policy in force when they were registered, so older splits must still name the value they were created with. | Parameter | Type | Required | Notes | |---|---|---|---| | `dataset_id` | string | yes | | | `policy` | string | yes | | | `dry_run` | boolean | no | Default: `false` | ## data_resample Resample time bars onto activity, and report whether it actually helped. Time bars sample on a clock the market does not follow: activity arrives in bursts, so quiet periods are oversampled and busy ones undersampled. The resulting fat tails break every normality-based Sharpe statistic — a return kurtosis of 18 makes the usual inference meaningless. Dollar and volume bars sample on activity instead. The comparison is returned rather than assumed, because resampling does not always help and claiming it did would be its own kind of lie. | Parameter | Type | Required | Notes | |---|---|---|---| | `dataset_id` | string | yes | | | `method` | string | no | Default: `"dollar"` | | `target_bars` | integer | no | aim for roughly this many bars; omit for a quarter of the source | ## split_register Register train/validate/test/holdout ranges. Immutable once created. Registering the split before you look at any result is what stops 'out-of-sample' from being redefined after the fact. The holdout range is stored but its bars are not readable through any tool except holdout_evaluate. | Parameter | Type | Required | Notes | |---|---|---|---| | `dataset_id` | string | yes | | | `train` | string[] | yes | [start, end) ISO8601 | | `validate` | string[] | yes | | | `test` | string[] | yes | | | `holdout` | string[] | yes | | | `embargo_bars` | integer | no | Default: `0` | | `label` | string | no | | ## data_ingest_universe Backfill a basket of instruments and register it as a universe. Testing one spec across many instruments is the only way to genuinely increase effective sample size. Resampling the same history to a finer grid adds autocorrelated bars, not information, and does not lower the deflated Sharpe hurdle — which is denominated in years, not observations. | Parameter | Type | Required | Notes | |---|---|---|---| | `name` | string | yes | a label for the basket, e.g. 'top30-usd' | | `timeframe` | string | yes | | | `start` | string | yes | | | `end` | string | yes | | | `symbols` | string[] | no | explicit basket; omit to take the most liquid USD pairs | | `top_n` | integer | no | Default: `30` | | `min_volume_24h_usd` | number | no | Default: `5000000` | | `client_request_id` | string | no | | ## universe_catalog Registered baskets and their measured breadth. Takes no parameters. ## backtest_cross_section Run one spec across a whole universe. Adds exactly ONE trial to N. The spec is the hypothesis and the assets are the sample, so charging one trial per asset would penalise the statistically correct thing. Returns the cross-sectional Sharpe distribution plus a pooled estimate whose standard error uses M_eff — the effective number of independent tests — rather than the raw asset count. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `universe_id` | string | yes | | | `segment` | string | no | Default: `"train"` | | `params` | object | no | | | `client_request_id` | string | no | | ## stats_effective_tests How many independent tests a basket actually provides. Crypto co-moves. Thirty assets are not thirty confirmations, and booking them as such would replace one overfitting mechanism with another. | Parameter | Type | Required | Notes | |---|---|---|---| | `universe_id` | string | yes | | | `segment` | string | no | Default: `"train"` | | `split_id` | string | no | | ## cost_model_refresh Pin the current fee tier server-side. The caller cannot supply fee assumptions anywhere in this server. Whatever this returns is stamped onto every run that follows. | Parameter | Type | Required | Notes | |---|---|---|---| | `venue` | string | no | Default: `"coinbase"` | ## cost_breakeven What the edge must clear before any signal is worth discussing. Call this before designing a strategy. If the required edge per trade exceeds anything plausible at your intended frequency, the frequency is wrong and no signal will fix it. | Parameter | Type | Required | Notes | |---|---|---|---| | `trades_per_day` | number | yes | | | `execution` | string | no | Default: `"taker"` | | `cost_model_id` | string | no | | ## strategy_register Register a strategy spec. Identity is the sha256 of the canonical spec. The spec is a small declarative graph — named features with explicit lags, plus entry/exit predicates — precisely so feature_validate can analyse it for look-ahead. Arbitrary Python could not be checked. | Parameter | Type | Required | Notes | |---|---|---|---| | `spec` | object | yes | | | `family` | string | no | Default: `"default"` | ## feature_validate Static look-ahead analysis of the feature graph. Catches the most common backtest lie before it costs a run: negative lags, forward-looking ops, and statistics fitted over the whole sample. A feature reading close[t] is fine here because execution is next-bar-open and the server enforces that. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | ## strategy_freeze Lock the spec, pinning a parameter vector into it. Irreversible. Required before the holdout and before any paper session. Freezing forces you to commit to one configuration rather than deciding which one you meant after seeing the holdout. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `params` | object | no | | | `dry_run` | boolean | no | Default: `false` | ## family_fork Start a new trial-counting family, recording why. Strict accounting: a fork does not reset N. The lineage is walked when N is computed, because you did learn from the parent's trials. The justification is stored in the ledger so the reset is auditable rather than silent. | Parameter | Type | Required | Notes | |---|---|---|---| | `new_family` | string | yes | | | `parent_family` | string | yes | | | `justification` | string | yes | | ## library_search Documented strategy hypotheses with an economic rationale. The reason this exists: a parameter search has no prior, and a search without a prior finds whichever configuration traded least in a rising market. Every entry here states who is on the other side of the trade and why they lose, so a result can be judged against a hypothesis rather than a curve fit. Citations are model-generated leads to check, NOT evidence. `citation_verified` is false until a human has actually looked the source up. | Parameter | Type | Required | Notes | |---|---|---|---| | `category` | string | no | time-series momentum and trend following · mean reversion and statistical arbitrage · volatility, risk premia and regime filters · cross-sectional momentum, carry and relative value · calendar effects, flow and microstructure | | `max_trades_per_day` | number | no | filter to ideas cheap enough for the pinned fee tier | | `survives_cost` | boolean | no | | | `limit` | integer | no | Default: `15` | ## library_get The full entry: rationale, origin, failure modes, and the falsification test. | Parameter | Type | Required | Notes | |---|---|---|---| | `name` | string | yes | | ## library_adopt Register a library hypothesis as a strategy in your own family. This is the point of the library: the idea enters the ledger with a recorded provenance, so a later result can be traced to the hypothesis that motivated it rather than to a sweep that found it. | Parameter | Type | Required | Notes | |---|---|---|---| | `name` | string | yes | | | `family` | string | no | | ## case_studies Documented strategy failures, with the mechanism and what would have caught it. Companion to the strategy library: that gives hypotheses with a prior, this gives failure modes with a mechanism. Useful when a result looks good and you want to know which known way it might be wrong. Sources are model-generated leads and are NOT verified. | Parameter | Type | Required | Notes | |---|---|---|---| | `category` | string | no | classic_blowups \| crypto_blowups \| backtest_lies \| data_traps \| overfit_famous | | `search` | string | no | match mechanism or strategy | | `limit` | integer | no | Default: `8` | ## case_study The full record for one documented failure. | Parameter | Type | Required | Notes | |---|---|---|---| | `slug` | string | yes | | ## backtest_submit Queue a backtest. Adds exactly one trial to N. Execution is next-bar-open and enforced server-side. Costs come from the latest pinned cost model; there is no fee parameter. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `segment` | string | no | Default: `"train"` | | `params` | object | no | | | `execution` | string | no | Default: `"taker"` | | `client_request_id` | string | no | | ## sweep_submit Queue a parameter sweep. Every point is a trial. The updated N is returned immediately, before any result arrives, so the statistical cost of the sweep is visible while you can still cancel it. Sweeping 2,000 points to find a winner shows up as N=2000 in every deflated Sharpe you compute afterwards. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `param_grid` | object | yes | {'fast': [5,10,20], 'slow': {'start':50,'stop':200,'step':25}} | | `segment` | string | no | Default: `"train"` | | `max_points` | integer | no | Default: `500` | | `dry_run` | boolean | no | expand the grid and report the cost to N without queueing anything Default: `false` | | `client_request_id` | string | no | | ## job_status Poll a submitted job. | Parameter | Type | Required | Notes | |---|---|---|---| | `job_id` | string | yes | | ## backtest_result Fetch the metric summary for one recorded run. Around twenty numbers, never a trade blotter. Gross and net sit side by side so fee drag is impossible to overlook. The full return series is available as a resource at quant://runs/{run_id}/returns. | Parameter | Type | Required | Notes | |---|---|---|---| | `run_id` | string | yes | | ## stats_deflated_sharpe Deflated Sharpe for one run, against the family's trial count. N is read from the ledger. It is not an argument, and cannot be. | Parameter | Type | Required | Notes | |---|---|---|---| | `run_id` | string | yes | | ## stats_bootstrap_ci Stationary-bootstrap confidence intervals for Sharpe and expectancy. A point estimate from a few dozen trades is not a measurement. Expect the interval on a marginal strategy to include zero; that is the tool working. Block length respects serial dependence, so the interval does not inherit the false precision an iid bootstrap would give. | Parameter | Type | Required | Notes | |---|---|---|---| | `run_id` | string | yes | | | `n_boot` | integer | no | Default: `2000` | | `confidence` | number | no | Default: `0.95` | ## stats_pbo Queue combinatorially symmetric CV to measure overfitting probability. Asks whether the configuration that looked best in-sample tends to land above or below the out-of-sample median. Above 0.5 means your selection procedure is anti-predictive. Uses the family's evaluated parameter vectors unless you pass a grid; the re-evaluations are recorded but deliberately excluded from N. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `n_groups` | integer | no | number of equal subsets; forced even, since CSCV splits them in half Default: `8` | | `segment` | string | no | Default: `"train"` | | `param_grid` | object | no | | | `client_request_id` | string | no | | ## stats_reality_check Queue White's Reality Check, Hansen's SPA and Romano–Wolf on a family. Tests the best member against the whole family it was selected from, using a stationary bootstrap that preserves serial dependence. Testing the winner in isolation answers a question nobody asked. | Parameter | Type | Required | Notes | |---|---|---|---| | `family` | string | yes | | | `benchmark` | string | no | Default: `"zero"` | | `n_boot` | integer | no | Default: `1000` | | `client_request_id` | string | no | | ## stats_min_backtest_length MinBTL = 2·ln(N) / E[max_N]² — how much data N trials actually require. Frequently the tool that ends a line of research early, which is the point. | Parameter | Type | Required | Notes | |---|---|---|---| | `family` | string | yes | | ## experiment_ledger The audit trail: N, the Sharpe distribution, and the extremes. Read-only, and append-only underneath — N can never be revised downward. | Parameter | Type | Required | Notes | |---|---|---|---| | `family` | string | yes | | | `limit` | integer | no | Default: `10` | ## stats_triple_barrier Label every candidate entry by which barrier it would have hit first. A strategy that trades twenty times in two years cannot be evaluated. This scores each potential entry against a profit-take, a stop and a time limit, which enlarges the evidence base without increasing trading frequency — the central tension in this system. When both price barriers fall inside one bar the stop is taken: a bar cannot resolve which was touched first, and the adverse assumption is the only one that does not flatter the result. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `pt_bps` | number | no | profit-take barrier Default: `200.0` | | `sl_bps` | number | no | stop-loss barrier Default: `100.0` | | `vertical_bars` | integer | no | Default: `48` | | `segment` | string | no | Default: `"train"` | ## gate_check Run the statistical gauntlet. Passing is what unlocks the holdout. Seven checks, including the Harvey–Liu t > 3 hurdle rather than the conventional t > 2, and regime survival tested separately in bull, bear and chop rather than in aggregate. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | ## holdout_evaluate Spend the one holdout attempt for this frozen strategy. Requires the strategy to be frozen and gate_check to have passed against that exact spec hash, with no prior grant. Every attempt is logged whether or not it succeeds. There is no second attempt, ever. Pass dry_run=true to check every precondition and see what would happen without spending the grant or logging an attempt. A tool this expensive should be inspectable before it is fired. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `dry_run` | boolean | no | check every precondition and report what WOULD happen, then refuse. Spends nothing and is not logged as an attempt Default: `false` | ## execution_replay_submit Queue an event-driven revalidation with honest fill modelling. Resting post-only limits fill only when the bar actually trades through the level, capped by volume participation, and are cancelled unfilled after max_wait_bars. A resting order that never fills is simulated as never filling — assuming fills at the touch is the second-most-common backtest lie after understating costs. Does not add to N: it revalidates an existing trial rather than creating a new one. | Parameter | Type | Required | Notes | |---|---|---|---| | `strategy_id` | string | yes | | | `split_id` | string | yes | | | `segment` | string | no | Default: `"test"` | | `post_only` | boolean | no | Default: `true` | | `offset_bps` | number | no | Default: `1.0` | | `participation` | number | no | Default: `0.05` | | `max_wait_bars` | integer | no | Default: `3` | | `engine` | string | no | Default: `"native_l1"` | | `client_request_id` | string | no | | ## paper_session Forward-test a frozen strategy on bars that did not exist at build time. The only validation that cannot be overfit. 'start' opens a session against a frozen spec, 'record' evaluates newly printed bars and logs signals, 'report' summarises forward performance after the pinned cost model. | Parameter | Type | Required | Notes | |---|---|---|---| | `action` | string | yes | | | `strategy_id` | string | no | | | `session_id` | string | no | | | `dataset_id` | string | no | | ## server_status What this server is, what it holds, and what has changed recently. Call this first in a new conversation. It is cheaper than rediscovering the state by trial and error, and it will tell you which research lines are already closed. Takes no parameters. ## account_status Your plan, this month's usage, and what remains. The metered unit is the trial, not the API call — every trial permanently raises the bar your own results must clear, so it is the scarce thing worth pricing. A smaller sweep buys a lower deflated-Sharpe hurdle as well as a smaller bill; the constraint runs with the statistics rather than against them. Takes no parameters. ## plans What each plan includes. Takes no parameters.