Authoring in Rust
The seam a native strategy implements, the reader convention its parameters follow, and the folder that compiles a user strategy into your own binary.
A native strategy in Vike Trader is a type that implements
Strategy over a broker bound. Choose the bound first, because it is what
the type system uses to document where the strategy can run.
impl<B: Broker> Strategy<B>— PORTABLE. The same type runs in the backtest sweep harness and on a live mount unchanged.Grid,DcaAccumulate,FundingCapture,PairsZScoreandBuyHoldall take it — but the bound is a compile-time property, not a mount permission:funding_captureandpairs_zscorecarry a writtenLIVE_CAPABLEreason the daemon refuses at profile load.impl<B: HftBroker> Strategy<B>— portable, but only over a broker that can resolve a strategy-chosen TAG to a resting order and re-price or cancel it in place.SpreadMakerandTrailingScalpertake this bound; a plainBroker-only engine simply cannot mount them.impl Strategy<SimBroker>— a deliberate, load-bearing SECOND form, not a backlog item. It is how a strategy says "I drive simulator machinery" — a position sizer, the shared-cash gate, an attached protective stop, a symbol universe, a bar-count schedule — and the type is what stops it being mounted live. See simulator-only strategies.
What the reference strategies show
crates/vike-strategy/src/grid_dca.rs states the constraint that shapes most portable designs: the
portable Broker surface is the common denominator of the two stacks, and it deliberately has NO
cancel — only the concrete brokers expose one. Grid and DcaAccumulate are therefore designed
to need none, and the module is honest about the price: a resting limit placed before a halt or a
take-profit cannot be pulled, so Grid re-flattens every bar while halted and DcaAccumulate may
re-fill a prior cycle's residual entries. Both are documented, bounded-per-cycle behaviours.
crates/vike-strategy/src/funding_capture.rs shows the other way out of the same constraint: it
steers a NET position with market deltas and never rests a limit, so it needs no cancel at all.
crates/vike-strategy/src/pairs.rs shows a strategy written as a MEASUREMENT INSTRUMENT rather than
a product — its own header says to expect a negative result and that this is the successful outcome.
None of these are parity-gated: they are net-new Rust surface with no Python twin, so what is tested
is behaviour (does the ladder rest, fill, re-arm and stop as designed?) rather than an f64 oracle.
The parameter reader convention
Nearly every from_params in the workspace is a READER, not a schema: it reads a toml::Value,
ignores what it does not recognise, and falls back to a compiled default for anything missing.
Follow it — but understand what it costs. A lenient reader cannot fail, so an unrecognised key
silently leaves its knob at the default, and so does a recognised key carrying a value of the wrong
type. That is why the registry publishes PARAM_KEYS and
PARAM_ROUTES for the built-in names, so a live mount can refuse the table instead of trading it.
The exception worth knowing is vike_mm::SpreadMaker::from_params (behind the spread_maker and
gueant_maker registry names): it returns a Result, and its eight enum keys — variance_mode,
horizon_mode, price_domain, spread_model, reservation_model, spread_source, kappa_mode
and style — refuse the table when PRESENT but naming no variant, or carrying a value that is not
a string at all, rather than quietly running a different model than the profile names. Its numeric
keys, and an absent key of any kind, stay lenient like everything else.
A strategy as a crate
vike-user-strategies is the compiled user-strategy HOST. Its build.rs scans
<workspace>/user_data/strategies/rust/<name>/
├─ <name>.rs entry file — the stem MUST equal the folder name
├─ strategy.toml optional: `live = true` opts into live mounting
└─ *.toml presets (loaded by vike-studio-core, not by this scan)and generates the registry the crate re-exports — USER_STRATEGIES, USER_LIVE_CAPABLE and
user_strategy_by_name. The built-in registries consult it AFTER every built-in arm, so a user
folder can never shadow a built-in name, and NO framework crate changes when a strategy is added: a
new native strategy is a new folder, nothing else. VIKE_USER_DATA_DIR overrides the scanned root
at build time. A folder name must be a lowercase Rust-identifier-safe token, because the generated
module and match arm are built from it, and a malformed folder is a build ERROR naming the path —
silence is how this tier spent months being mistaken for a working mechanism.
The entry file's contract is one function:
pub fn build<B: vike_model::HftBroker + 'static>(
params: &toml::Value,
) -> Box<dyn vike_model::Strategy<B> + Send>The separate crate is the load-bearing part. User entry files compile as modules of THAT crate — a
separate compilation unit from the framework's own strategy layer — so they resolve only the
platform's PUBLIC API, reached through its dependencies: vike-model, vike-strategy,
vike-indicators and toml. An internals refactor can never break a user strategy, and a user
strategy can never grow a load-bearing dependency on a crate-private detail.
Two things the tier does not do for you
The in-tree PARAM_KEYS and param-gate tables cover the REFERENCE set only. They do not cover user
strategies, so a typo'd key in your own build silently reads as the compiled default. And
strategy.toml's live = true is an explicit opt-in: an absent file or an absent key means
sim-only, the default-deny posture.
With no user_data/ — every fresh clone, every CI checkout — the generated registry is EMPTY and
the host crate is inert, answering None for every name. The pipeline is still proven on every CI
run through a committed fixture tree. User code compiles only in a source checkout and into the
operator's OWN binary; user_data/ is gitignored and never enters the repository.
For strategies written as files rather than as Rust, see scripting; for running what you have written, see backtesting.
The position executor
One position, driven from Pending to Closed over a portable Broker — the lifecycle states, the triple barrier and its fixed precedence, and the realized-PnL law.
Simulator-only strategies
The 7 strategy names a backtest resolves that a live daemon cannot, each with the registry's own reason — plus the script arm that resolves by path, not by name.