vike
Tools

run_sweep

Expand a profile's parameter grid on the datahub and get every point back ranked best-first, each with its own report.

Runs a parameter-grid sweep on the remote vike-datahub server and returns the ranked SweepReport. Same input as run_backtest — a profile TOML, optionally with a Rhai script injected — plus one grid table and one ranking knob.

Input

FieldTypeRequiredMeaning
profilestringyesProfile TOML with [data], [strategy] and [sweep] (plus optional [engine])
scriptstringnoRhai source, injected as [strategy.params].src
rank_bystringnosharpe (default), return, max_dd or equity — applied server-side

The [sweep] table is the whole grid: each key names a strategy.params field and each value is an array to cross-product over. expand_sweep turns the profile into that cartesian product of single-run profiles, each with its params overridden per point and its own sweep field cleared — so every expanded point is itself a plain, runnable single-backtest profile. A profile with no [sweep] table comes back as a server-side error that quotes the fix.

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_sweep","arguments":{
  "profile": "[data]\nvenue = \"binance\"\nsymbols = [\"BTCUSDT\"]\nkind = \"bar\"\nfrom = \"0\"\nto = \"100000\"\n\n[strategy]\nname = \"buy_hold\"\n\n[sweep]\nfast = [5, 10]\n",
  "rank_by": "sharpe"
}}}

run_tools_reject_a_missing_profile_arg_before_any_connect pins the local half: a missing profile, or a script injection into unparsable TOML, errors before a socket is opened. Everything else is the server's answer, because the TOML ships verbatim and BacktestProfile::from_toml_str is the only parser.

Ranking happens on the server

rank_by is resolved by the canonical harness::RankMetric::from_str_ci. An unrecognized value is a clean error naming the valid set — never a silent fallback to the default — and an omitted one ranks by Sharpe, matching the shipped backtest bin. Direction is folded in: sharpe, return and equity sort descending, max_dd ascending, because a smaller drawdown is better. A NaN key — a Sharpe over a zero-variance curve, say — sorts last among the successes, so a degenerate point can never rank first, and rows whose run failed always sort behind every success.

No client re-implements a metric. The ranking runs over real BacktestReports with the canonical comparator, which is the same rule that took sharpe and max-drawdown out of the vike-cli sweep verb: nothing outside vike-backtest computes them.

What comes back

{ "sweep": … } wrapping a SweepReport: rows plus the rank_by it was ranked under. Each SweepRow carries

  • overrides — the (key, value) pairs that produced this point,
  • report or error — never both; a point that failed records its error string and is not dropped,
  • score — stamped only by the objective path, and skipped on serialization otherwise, so a default sweep's JSON is unchanged by the seam's existence.

Read the head of rows as the winner and the tail for what broke. Sweeps documents the expansion, objectives the pluggable scalar the score field belongs to, and search the successive-halving and TPE lanes that fold through the same per-point plumbing.

Determinism, and the memory shape

Points run on a rayon pool, and the ordering does not depend on scheduling: the collect is order-preserving and the ranking sort is stable over that input, so a parallel sweep's bytes equal the one-at-a-time loop's — parallel_and_sequential_sweeps_are_byte_identical is the pin.

Parallelism multiplies the data slice, not just the CPU

The shared store handle is shared; the data is not. Every point independently re-scans and fully materializes its own slice, so peak memory and store I/O are N_threads x slice. The pool is therefore bounded rather than one worker per core — min(4, available_parallelism()) by default, raised by VIKE_SWEEP_THREADS on the server, and pinned back to one at a time by VIKE_SWEEP_SEQUENTIAL=1. On a large recorded tick slice an uncapped sweep is an OOM shape, and these sweeps often run on a box that also hosts live trading. Size the multiplier against the slice, not against the core count.

The keyed-datahub and unreachable-server behaviour is identical to run_backtest's: every Run* verb is control scope because it compiles client-supplied Rhai, and a connect failure is a clean tool error.

The prompt

Sweep fast over 5, 10 and 20 against slow over 50 and 100, rank by Sharpe, and show me the top three rows with their parameters.

A grid returns its best row whether or not the edge survives out of sample — follow it with run_walk_forward. The human twin is vike-cli sweep; the guide is Run a sweep on the data service.

On this page