builder_add_conditionSave a typed condition definition.
Area
Strategy Builder
Group
Authoring
Access
Write
Risk
May change server state
Details
Full description
Details
Save a typed condition definition. Returns definition_id, source_version and name.
Multi-timeframe: set 'resolution' inside left/right value refs, e.g.: {"kind": "compare", "left": {"kind": "indicator", "indicator": "ema", "period": 14, "resolution": "4h"}, "op": ">", "right": 50} For a known value ref, use builder_discover(action='get', ref='value_ref:indicator') for the direct schema; otherwise use builder_discover to find its typed ref first.
Cross-instrument market gate (e.g. "only long when SPY is in uptrend"): {"kind": "compare", "left": {"kind": "price", "field": "close", "symbol": "SPY"}, "op": ">", "right": {"kind": "indicator", "indicator": "ema", "period": 200, "symbol": "SPY"}}
Cross-symbol arithmetic: set 'symbol' inside a price/indicator value ref to read that field from ANOTHER instrument, then combine with binary_expr. Relative strength vs a benchmark (this name's RSI minus SPY's RSI): {"kind": "compare", "left": {"kind": "binary_expr", "op": "-", "left": {"kind": "indicator", "indicator": "rsi", "period": 14}, "right": {"kind": "indicator", "indicator": "rsi", "period": 14, "symbol": "SPY"}}, "op": ">", "right": 0} Prefer normalized operands (rsi, percentile, xs_zscore) when the two instruments trade at different price scales: a raw close-minus-close difference between, say, a $100 stock and $60,000 BTC is dominated by the larger quote and is effectively a constant. 'symbol' cannot be combined with 'resolution' on the same ref, and is rejected inside the per-sibling source of rank/xs_zscore/xs_dispersion operands (an absolute symbol there makes every sibling resolve the same value).
Event payload fields: event_type_id identifies the feed; event_field is the scalar value ref used in compare/cross conditions. Do NOT use {"kind": "event_type"} as left/right — event_type is not a value-ref discriminator. For a caller's own custom event types, pass the bare slug you registered (e.g. 'my-signal'), not the full internal custom.{uid}.{slug} storage id.
Compare a macro/event payload field against a constant: {"kind": "compare", "left": {"kind": "event_field", "event_type_id": "macro.fed_balance_sheet", "event_field": "ratio"}, "op": ">", "right": 1.0}
event_field is valid on right too, for event-provided thresholds: {"kind": "compare", "left": {"kind": "price", "field": "close"}, "op": ">", "right": {"kind": "event_field", "event_type_id": "macro.fed_balance_sheet", "event_field": "threshold"}}
Bidirectional event entries: add one event_field compare definition and attach it as entry direction="long"; add another event_field compare definition and attach it as entry direction="short". Long and short entry groups are alternatives; same-bar reversal remains disabled. builder_add_condition only creates a definition; it is inert until builder_attach_rule wires it into entry/exit/gate. After adding event definitions, call builder_get_strategy and confirm they appear in builder.rules and entry_groups, not unattached_definitions. Directional exits must also be attached to their side, e.g. role="exit", direction="long" and role="exit", direction="short".
Cross-sectional conditions (multi-sleeve / universe strategies only — single-symbol strategies reject these at compile time). Each compares this sleeve's value against portfolio siblings on the current bar. builder_discover(action='list', filters={'families': ['cross_sectional']}) lists every cross-sectional condition and value ref. The same measures are also value refs ("rank", "xs_zscore", "xs_dispersion", "sibling") that go wherever a compare, cross, range, in_set or transition accepts a value; they are refused in a sizing formula, a fixed_targets stop_loss_price_ref, a shared signal and an allocation score, which are evaluated for one symbol at a time.
Top-decile momentum (rank in the upper 10% of the universe): {"kind": "compare", "left": {"kind": "rank", "source": { "kind": "indicator", "indicator": "roc", "period": 20}}, "op": ">", "right": 0.9}
Pairs trade leg (long this sleeve when its close < QQQ's close): {"kind": "compare", "left": {"kind": "price", "field": "close"}, "op": "<", "right": {"kind": "sibling", "symbol": "QQQ", "source": {"kind": "price", "field": "close"}}}
Operates on
Builder objects this tool reads or produces, linked to their reference pages.
Capabilities
Bounded options and operating modes surfaced above the full JSON schema.
Required Inputs
conditionobjectTyped condition source with a consistent "kind" discriminator. Use builder_discover(action='get', ref=<ref>) for a known kind's direct schema. Otherwise start with builder_discover(action='facets'), then list exact filters and get a returned ref. For saved named zones, create the zone with builder_save_zone, then use compare/cross with value_ref:named_zone on left/right. Inspect 'pattern:named_zone_compare', 'pattern:named_zone_cross', and 'value_ref:named_zone' for examples.strategy_idstringStrategy ID from create_strategyOptional Inputs
nameanyOf (2 variants)Optional strategy-scoped agent-facing identifier (snake_case, ≤48 chars, leading letter, unique within strategy, cannot be 'entry'/'exit'/'gate'/'overlay' or match the auto-ID shape 'c_<8 hex chars>'). If omitted, a deterministic name is auto-generated from the condition spec (e.g. 'close_gt_ema20'). Use this name when addressing the definition in sweep override labels: {"label": "entry.<name>", ...}. Rename later via builder_rename_definition.scan_run_idanyOf (2 variants)Optional ID of the signal scan run that validated this condition. Pass this when adding a condition that was validated by signal_scan to link the evidence back to the definition.