Skip to content

Strategy Reference

Strategy files define a single entry engine plus an exit condition composed of predicates. At runtime the parser converts the YAML into StrategyConfigData, feeds it to the signal generator, and enriches all generated trades with entry metadata.

flowchart LR
    Metrics[Metric snapshot] --> Predicates
    Predicates -->|all true| EntryEngine
    EntryEngine -->|should_open?| Backtest
    Backtest --> Trades
    ExitPredicates[Exit predicates] --> Backtest
    Backtest -->|exit signal| Trades
schema_version: "1.0"
strategy:
  name: threshold_reversion_strategy
  entry:
    name: threshold_reversion_entry
    engine: threshold_reversion
    params: {...}
    predicates: [...]
  exit:
    name: default_exit
    predicates: [...]

Entry Blocks

Every entry block contains:

Field Description
name Free-form label written to trade metadata (e.g., reason).
engine Identifier resolved via ENTRY_ENGINE_REGISTRY.
params Mapping validated against the engine’s dataclass.
predicates Optional list of predicate definitions. All predicates must pass for the engine to emit an open signal.

Predicates use the following schema:

Field Type Required Notes
metric string Yes Dot-referenced metric key (e.g., z30m.z_score).
operator string Yes One of <, <=, >, >=, ==, !=.
value number ◻️ Literal RHS. Mutually exclusive with other_metric.
other_metric string ◻️ Metric key to compare against. Mutually exclusive with value.
use_abs bool ◻️ Apply abs() to the left-hand side before comparison. Defaults to false.

Missing metrics or non-finite values cause the predicate to evaluate to false. Duplicate predicates (same combination of fields) are rejected during parsing.

threshold_reversion

Mean-reversion entry engine driven by the compiled ThresholdReversionMetric. Tracks a reference price, waits for deviations beyond threshold_pips, and emits long/short signals with TP/SL levels derived from the configured multiples.

Parameter Type Required Default Description
lookback_seconds int Yes - Horizon for establishing the reference price.
threshold_pips float Yes - Minimum distance from the reference mid required to trigger a signal.
tp_pips float No threshold_pips Take-profit distance in pips (must be positive).
sl_pips float No threshold_pips Stop-loss distance in pips (must be positive).
min_recency_seconds float No 0.0 Minimum age of the reference before a new trade can open. Helps avoid rapid flip-flops.
trade_timeout_seconds float No null Optional timeout after which positions auto-close (TIMEOUT).

Metadata emitted on trade open - direction (1 for long, -1 for short) - signal_price - threshold, threshold_pips - tp_price, sl_price - reference_price, reference_age_seconds - position_open_age_seconds - trade_timeout_seconds

Behavioural notes - The engine prevents back-to-back entries in the same direction until the metric reverts. - signal_price records the market mid when the signal fired. - In the backtest loop, executed TP/SL are re-anchored from the realized fill price for threshold-based entries, so configured pip distances match the actual filled trade rather than the earlier signal tick. - Pair-specific pip_size (from the backtest config) determines the conversion of pip distances into absolute prices.

Example:

entry:
  name: threshold_reversion_entry
  engine: threshold_reversion
  params:
    lookback_seconds: 1800
    threshold_pips: 8
    tp_pips: 8
    sl_pips: 12
    min_recency_seconds: 90
    trade_timeout_seconds: 3600
  predicates:
    - metric: spread_60s.spread_percentile
      operator: "<"
      value: 0.4
    - metric: tick_rate_30s.tick_rate_per_min
      operator: ">"
      value: 80

ewma_crossover

Trend-following engine that watches two metrics (typically EWMAs) and fires when the difference changes sign.

Parameter Type Required Default Description
fast_metric string Yes - Metric key representing the faster series (e.g., ewma_mid_5m.ewma).
slow_metric string Yes - Metric key representing the slower series.
long_on_cross bool No true Emit a long signal when fast crosses above slow.
short_on_cross bool No false Emit a short signal when fast crosses below slow.
tp_pips float No 0.0 Optional take-profit distance in pips (0 disables TP).
sl_pips float No 0.0 Optional stop-loss distance in pips (0 disables SL).
trade_timeout_seconds float No null Optional timeout for open positions.

Metadata emitted on trade open - fast, slow (the sampled metric values) - diff (fast − slow; sign change indicates crossover) - direction - signal_price

Behavioural notes - The engine remembers the previous difference; the very first observation seeds state but does not open a position. - Both tp_pips and sl_pips are optional. Set to zero to leave TP/SL unset and rely on exit predicates. - Supports asymmetric configurations (e.g., only long or only short trades).

Example:

entry:
  name: crossover_entry
  engine: ewma_crossover
  params:
    fast_metric: ewma_mid_5m.ewma
    slow_metric: ewma_mid_30m.ewma
    long_on_cross: true
    short_on_cross: true
    tp_pips: 6
    sl_pips: 9

stub

Engine id: stub
Class: NullEntryEngine

A no-op engine used in smoke tests and dry runs. It never opens trades and ignores predicates apart from evaluation.

Parameter Type Required Default Description
(none) - - - Only the wrapper fields (name, enabled) are honoured.

Exit Blocks

Exit definitions contain:

Field Description
name Label recorded as the exit reason when predicates trigger (EntryResult.close_reason).
predicates List of predicates with the same schema used for entries. All must evaluate to true on a tick for an exit signal to be emitted.

Typical exit:

exit:
  name: default_exit
  predicates:
    - metric: ewma_mid_5m_slope.slope
      operator: "<"
      value: 0

If you omit predicates the exit never forces a close - trades stay open until TP/SL/timeout conditions fire.


Putting It Together

Example strategy referencing the metrics catalogue:

schema_version: "1.0"
strategy:
  name: mean_reversion_v1
  entry:
    name: threshold_reversion_entry
    engine: threshold_reversion
    params:
      lookback_seconds: 1200
      threshold_pips: 7.5
      tp_pips: 8
      sl_pips: 9
      min_recency_seconds: 120
    predicates:
      - metric: spread_60s.spread_percentile
        operator: "<"
        value: 0.5
      - metric: ewma_vol_5m.vol_percentile
        operator: "<"
        value: 0.8
  exit:
    name: volatility_exit
    predicates:
      - metric: ewma_vol_5m.vol_percentile
        operator: ">"
        value: 0.9

This strategy: - enters on threshold reversions when spreads are tight and short-term volatility is subdued, - keeps trades open until either TP/SL/timeout hits or the volatility percentile climbs above 0.9.


Tips & Best Practices

  • Entry/exit predicates run on the current metric snapshot. Ensure referenced metrics are enabled and produce finite values under expected conditions.
  • Keep predicate combinations unique; duplicate definitions within the same block are rejected during parsing.
  • Use trade_timeout_seconds sparingly - timeouts close trades with TIMEOUT reason regardless of price.
  • Place derived metric names carefully; future code often expects dotted keys (e.g., ewma_vol_5m.vol_percentile).
  • When introducing new engines, remember to update ENTRY_PARAMS_REGISTRY, ENTRY_ENGINE_REGISTRY, and extend this reference to keep documentation aligned.