Scanning/Building Scan Payloads

    Scanning

    Building Scan Payloads

    This page builds scan payloads one filter category at a time. Every example is a complete request body for POST /api/v2/scan and runs as-is. Read How Scanning Works first for the model: universe, groups, filters and timeframes.

    You rarely start here

    Most payloads begin as a sentence sent to /scan/natural, or as Export filters from the scanr.ai scanner (see Get a payload). Use this page to read what those produce, check it, and make small edits by hand. An exported or generated payload is the object inside instructions in the examples below.

    All examples use the same universe (common stocks, ordinary shares and ADRs on the major U.S. exchanges) and sort largest-first, so only the filters change between them.

    The skeleton

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "PrevDayClose": [            { "State": { "Value": { "Lower": { "Operator": "gte", "Value": 5 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Three rules hold everywhere:

    • A category (Stock, Technical, …) maps a filter name to a list of rows. Two rows under one name are two separate conditions, and both must hold in an All group.
    • Send numbers as plain JSON numbers.
    • The catalog (GET /api/v2/scan/instructions) echoes descriptive fields such as DisplayName, Description, Type and InstructionType. Leave them out of your payload; the one exception is DisplayName on chart patterns (below).

    Stock filters

    Stock filters screen on quote and profile data: PrevDayClose, PrevDayVolume, TodaysVolume, Last, Change, ChangePercent, Gap, MarketCap, SharesFloat, SharesOutstanding, Week52High, Week52Low, Sector, Industry, Earnings and more.

    Numeric ranges take a Lower bound (gt or gte), an Upper bound (lt or lte), or both. Market cap is in dollars:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "MarketCap": [            {              "State": {                "Value": {                  "Lower": { "Operator": "gte", "Value": 300000000 },                  "Upper": { "Operator": "lt", "Value": 2000000000 }                }              }            }          ],          "PrevDayVolume": [            { "State": { "Value": { "Lower": { "Operator": "gte", "Value": 500000 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Price comparisons compare a level with the current price. Week52High with EqualTo and a WithinPercent tolerance finds stocks trading within 15% of their 52-week high:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "Week52High": [            { "State": { "Price": { "Comparison": { "EqualTo": true }, "WithinPercent": 15 } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Sector and industry take a list of names. The allowed names are in the catalog (Stock.Sector[0].State.Options) and at GET /api/v2/stocks/sectors and GET /api/v2/stocks/industries:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "Sector": [{ "State": { "Value": ["Healthcare"] } }],          "MarketCap": [            { "State": { "Value": { "Lower": { "Operator": "gte", "Value": 1000000000 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Technical studies

    Technical holds 100+ studies: moving averages (SMA, EMA, WMA, KAMA, …), momentum (RSI, MACD, STOCH, ADX, CCI, MFI, …), volatility (ATR, NATR, BBANDS), volume (OBV, AD, RELVOL_STDDEV) and statistics (LINEARREG_SLOPE, CORREL, STDDEV). Each row has:

    FieldMeaning
    TimeframeRequired. 1d, 1wk, 15m, … (see Timeframes).
    InputsThe series the study runs on, such as ["bar_close"] or ["bar_high", "bar_low", "bar_close"]. Use the study's default from the catalog unless you mean otherwise.
    ParamsThe study's parameters, each as { "Value": n }: { "Period": { "Value": 50 } }. Omitted parameters use their defaults.
    Returns.WantThe condition. Its key is the study's output plot name, and its value says what to compare the output with.
    WithinOptional. The condition may hold on any of the last N bars instead of only the latest.
    BarsAgoOptional. Evaluate the condition N bars back instead of on the latest bar.

    Plot names

    The key inside Want is an output name from the catalog's Returns.Plot. For most studies it is the study's own name, but not always:

    StudyPlot names
    SMA, EMA, RSI, ATR, ADXSame as the study: SMA, EMA, RSI, ATR, ADX
    MACDMACD, Signal, MACDHist
    BBANDSUpper, Middle, Lower
    STOCHSlowK, SlowD
    RELVOL_STDDEVVALUE

    Compare with a number

    RSI(14) below 30 on the daily chart:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Technical": {          "RSI": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 14 } },              "Returns": { "Want": { "RSI": { "Value": { "LessThan": 30 } } } }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    The comparators are GreaterThan, GreaterThanOrEqual, LessThan, LessThanOrEqual, EqualTo and NotEqualTo.

    Compare with the price

    Price compares the study with the current price, and reads study <comparator> price. "Price above its 200-day SMA" is therefore SMA LessThan price:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Technical": {          "SMA": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 200 } },              "Returns": { "Want": { "SMA": { "Price": { "Comparison": { "LessThan": true } } } } }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Compare with another study

    Study compares one study's output with another's. The inner study marks the output it contributes with "PlotChild": true. Add CrossesAbove or CrossesUnder to ask for a cross rather than a state, and Within to say how recent.

    A golden cross, the 50-day SMA crossing above the 200-day SMA in the last 5 sessions:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Technical": {          "SMA": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 50 } },              "Within": 5,              "Returns": {                "Want": {                  "SMA": {                    "Study": {                      "CrossesAbove": {                        "SMA": [                          {                            "Timeframe": "1d",                            "Inputs": ["bar_close"],                            "Params": { "Period": { "Value": 200 } },                            "Returns": { "Want": { "SMA": { "PlotChild": true } } }                          }                        ]                      }                    }                  }                }              }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    For "the 50-day is above the 200-day" (a state, not a cross), use GreaterThan and drop Within.

    Volume and liquidity

    RELVOL_STDDEV measures today's volume in standard deviations from its recent average; its plot name is VALUE. Pair it with an SMA of bar_dollar_volume to skip illiquid names. This is scanr.ai's Unusual Volume screen:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Technical": {          "RELVOL_STDDEV": [            {              "Timeframe": "1d",              "Inputs": ["bar_volume"],              "Params": { "Length": { "Value": 60 } },              "Returns": { "Want": { "VALUE": { "Value": { "GreaterThan": 3 } } } }            }          ],          "SMA": [            {              "Timeframe": "1d",              "Inputs": ["bar_dollar_volume"],              "Params": { "Period": { "Value": 50 } },              "Returns": { "Want": { "SMA": { "Value": { "GreaterThan": 10000000 } } } }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    The input series a study can read (bar_close, bar_volume, bar_dollar_volume, and more) are listed under Reference.ValidStudyInputs in the catalog.

    Indicator filters

    Indicator filters read scanr.ai's pre-computed scores for each stock:

    FilterRangeMeaning
    RelativeStrengthMkt1–99Percentile of trailing performance against the whole market. 99 is the strongest.
    RelativeStrengthSector1–99The same, against the stock's sector.
    RelativeStrengthIndustry1–99The same, against the stock's industry.
    TrendEfficiency0–100How cleanly the stock is trending rather than chopping.
    RegimeExtension−100–100How far price is stretched from its adaptive mean, in ATR units ×10.
    RegimeDivergence, RegimeDivergencePct−200–200, 1–99Extension relative to the stock's peer group, raw and ranked.
    GroupStrength−100–100The extension of the stock's sector or thematic ETF. Positive means the group itself is strong.
    MarketStrength, MarketEfficiency−100–100, 0–100The same readings for the broad market; identical for every stock.
    PETTM0 and upTrailing P/E. Loss-making companies have none and never match.

    Each row compares the score's Value. Leaders in strong groups (RS 80+ and a positive group):

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Indicator": {          "RelativeStrengthMkt": [            { "Returns": { "Want": { "Value": { "GreaterThanOrEqual": 80 } } } }          ],          "GroupStrength": [            { "Returns": { "Want": { "Value": { "GreaterThanOrEqual": 10 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Fundamental filters

    Fundamental filters read 300+ metrics from company filings: growth rates (Epsgrowth, Revenuegrowth, Revenueqoqgrowth), per-share figures (Dilutedeps), income, balance-sheet and cash-flow lines, and valuation ratios. Each row's State says which filing to read and what to compare:

    FieldMeaning
    FilingType10q (quarterly) or 10k (annual).
    WithinHow many recent filings to consider.
    LagHow many filings back to start: 0 is the latest, 4 is the same quarter a year earlier.
    WantsValueCompare with a number: SingleValue with one comparator set to true and a Value, or RangeValue with Lower and Upper.
    WantsOtherFundamentalCompare with another fundamental row, under Comp.

    Growth rates are fractions: 0.25 means 25%. Annual EPS growth of at least 25%, with the latest quarter's diluted EPS above the same quarter last year:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Fundamental": {          "Epsgrowth": [            {              "State": {                "FilingType": "10k",                "WantsValue": { "SingleValue": { "GreaterThanOrEqual": true, "Value": 0.25 } }              }            }          ],          "Dilutedeps": [            {              "State": {                "FilingType": "10q",                "Within": 1,                "Lag": 0,                "WantsOtherFundamental": {                  "GreaterThan": true,                  "Comp": {                    "Dilutedeps": [                      { "State": { "FilingType": "10q", "Within": 1, "Lag": 4 } }                    ]                  }                }              }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    The metric names are the keys of the catalog's Fundamental section.

    Candlestick patterns

    CandlestickPattern holds 60+ patterns named after their TA-Lib functions (CDLHAMMER, CDLMORNINGSTAR, CDLENGULFING, CDL3WHITESOLDIERS, …). Each row sets a Timeframe, the Inputs the pattern reads, and Within for how many recent bars may contain it. A hammer in the last 3 sessions, with RSI still below 40:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "CandlestickPattern": {          "CDLHAMMER": [            {              "Timeframe": "1d",              "Inputs": ["bar_open", "bar_high", "bar_low", "bar_close"],              "Within": 3            }          ]        },        "Technical": {          "RSI": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 14 } },              "Returns": { "Want": { "RSI": { "Value": { "LessThan": 40 } } } }            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Two-sided patterns

    Some patterns (CDLENGULFING, CDLHARAMI) fire in both directions. Set Direction on the row to keep one side: "bullish", "bearish", or "any" (the default). A bullish engulfing in the last 5 sessions is "CDLENGULFING": [{ "Timeframe": "1d", "Inputs": ["bar_open", "bar_high", "bar_low", "bar_close"], "Within": 5, "Direction": "bullish" }].

    SupportedDirections on each pattern in GET /api/v2/scan/instructions lists the sides it can fire. A side a pattern never fires, such as "bearish" on CDLHAMMER, is rejected. Sentiment is a descriptive label and does not filter.

    Chart patterns

    ChartPattern finds 17 detected formations: CupAndHandle, BullFlag, BearFlag, AscendingTriangle, DescendingTriangle, SymmetricalTriangle, DoubleBottom, DoubleTop, HeadAndShoulders, InverseHeadAndShoulders, RisingWedge, FallingWedge, ChannelUp, ChannelDown, HorizontalChannel, MultipleTop and MultipleBottom. Each row carries the pattern's DisplayName from the catalog (it identifies the pattern and must be kept), its direction, a Timeframe (5m, 1hr or 1d) and how far back to look:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "ChartPattern": {          "CupAndHandle": [            {              "DisplayName": "Cup and Handle",              "BullishBearish": "BULLISH",              "Timeframe": "1d",              "LookbackBars": 100            }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Copy each pattern's row from the catalog's ChartPattern section and change only Timeframe and LookbackBars.

    Excluding stocks

    An Exclude group removes its matches from the result. Large caps above their 50-day average, except financials:

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"]    },    "All": [      {        "Stock": {          "MarketCap": [            { "State": { "Value": { "Lower": { "Operator": "gte", "Value": 10000000000 } } } }          ]        },        "Technical": {          "SMA": [            {              "Timeframe": "1d",              "Inputs": ["bar_close"],              "Params": { "Period": { "Value": 50 } },              "Returns": { "Want": { "SMA": { "Price": { "Comparison": { "LessThan": true } } } } }            }          ]        }      }    ],    "Exclude": [      {        "Stock": {          "Sector": [{ "State": { "Value": ["Financial", "Finance, Insurance, And Real Estate"] } }]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    Universe restrictions

    Countries and themes narrow the universe before any filter runs. U.S. and Canadian companies in the silver-miners theme with RS above 70 (get real theme keys from GET /api/v2/scan/universe-themes):

    json
    {  "instructions": {    "Universe": {      "Exchange": ["nasdaq", "nyse", "amex", "arca", "bats", "bx"],      "Type": ["cs", "os", "adrc"],      "Country": ["us", "ca"],      "Theme": ["silver-miners"],      "ThemeMaxTier": 2    },    "All": [      {        "Indicator": {          "RelativeStrengthMkt": [            { "Returns": { "Want": { "Value": { "GreaterThanOrEqual": 70 } } } }          ]        }      }    ],    "Sort": { "field": "market_cap", "direction": "desc" }  }}

    An unknown theme key matches nothing rather than failing, so check keys against the theme list.

    Sorting

    Sort.field is one of market_cap, shares_out, shares_float or ticker; Sort.direction is asc or desc. Without a Sort, the order is unspecified.

    Common mistakes

    SymptomCause
    400 … Timeframe is required for technical studyEvery Technical row needs a Timeframe.
    400 … Invalid option on TimeframeUse the exact values: 1wk, not 1w; 1hr, not 1h.
    400 on CountryCountry codes are lower-case: us, not US.
    A study filter matches nothingThe Want key isn't the study's plot name (VALUE for RELVOL_STDDEV, SlowK for STOCH).
    ETFs or OTC names in the resultUniverse.Type or Universe.Exchange was left empty.
    Fewer matches than expected with All + AnyThey don't intersect; results are unioned. Put everything in one All group.

    Next