Cookbook

July 3, 2026 · View on GitHub

Ready-to-adapt ScanSpec recipes. Each is a complete spec — drop it in a file and run it with the CLI:

cargo run -p wickra-screener -- --spec recipe.json --data golden/data

The golden/specs/ directory holds these as runnable, byte-pinned fixtures.

Oversold reversal (mean reversion)

RSI is oversold or price closed below the lower Bollinger band:

{
  "universe": ["AAA", "BBB", "CCC"],
  "condition": {
    "type": "any",
    "conditions": [
      { "type": "cmp",
        "left":  { "kind": "indicator", "name": "Rsi", "params": [14] },
        "op":    "lt",
        "right": { "kind": "const", "value": 30.0 } },
      { "type": "cmp",
        "left":  { "kind": "price", "field": "close" },
        "op":    "lt",
        "right": { "kind": "indicator", "name": "BollingerBands", "params": [20, 2], "field": "lower" } }
    ]
  }
}

Golden-cross momentum

A fast EMA crossing above a slow EMA on the latest bar:

{
  "universe": ["AAA", "BBB", "CCC"],
  "condition": {
    "type": "cmp",
    "left":  { "kind": "indicator", "name": "Ema", "params": [7] },
    "op":    "crosses_above",
    "right": { "kind": "indicator", "name": "Ema", "params": [19] }
  }
}

Top-decile relative strength (cross-section)

Keep only the strongest 10-bar Roc symbols, ranked, best first:

{
  "universe": ["AAA", "BBB", "CCC", "DDD", "EEE"],
  "condition": {
    "type": "cross_section",
    "expr":   { "kind": "indicator", "name": "Roc", "params": [10] },
    "metric": "percentile_rank",
    "op":     "ge",
    "value":  0.9
  },
  "rank": { "by": { "kind": "indicator", "name": "Roc", "params": [10] }, "desc": true },
  "limit": 10
}

Breadth-gated longs

Only take individual RSI-momentum signals when the market is broadly healthy — at least 60% of the universe above its Sma(200):

{
  "universe": ["AAA", "BBB", "CCC", "DDD"],
  "condition": {
    "type": "all",
    "conditions": [
      { "type": "cmp",
        "left":  { "kind": "indicator", "name": "Rsi", "params": [14] },
        "op":    "gt",
        "right": { "kind": "const", "value": 55.0 } },
      { "type": "breadth",
        "inner": { "type": "cmp",
                   "left":  { "kind": "price", "field": "close" },
                   "op":    "gt",
                   "right": { "kind": "indicator", "name": "Sma", "params": [200] } },
        "op":    "ge",
        "ratio": 0.6 }
    ]
  }
}

Live scan (streaming)

The same spec, driven bar by bar instead of over history — see STREAMING.md:

from wickra_screener import Screener
s = Screener(open("recipe.json").read())
for symbol, candle in live_feed:
    s.command('{"cmd":"feed","symbol":"%s","candle":%s}' % (symbol, candle))
print(s.command('{"cmd":"evaluate"}'))   # JSON ScanReport of the current bar

See also