Scanner API

Introduction

Scanner API supports queries to dxFeed Scanner and is REST-based. The API has one static resource URL per method, accepts JSON-encoded request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and methods.

Scanner API supports the following methods:

  • /scanner/estimate - returns search result size estimates

  • /scanner/snapshot - performs search and returns JSON-encoded entities

  • /scanner/snapshot/csv - performs search and returns result in CSV format

Scanner Queries

A Scanner query is a JSON schema query with the following properties.

Property

Type

Description

Expected values

instrumentCategory*

String

The configuration includes one category

instrumentCategory: OPTION

or

instrumentCategory: UNDERLYINGS

datapoints

Array

Requested datapoints. In further query schema parts, a specific index references each datapoint as defined in this property

See ScanQuery.Datapoints for details

selectors

Array

JSON with select and value properties

See ScanQuery.Selectors for details

filters

Array

Filters applied to the query

See ScanQuery.Filters for details

sorters

Array

Sorting criteria applied to the query. It is represented as a set of sorters, where each sorter references a datapoint by its 0-based index as defined by the datapoints' value. The default order is descending or ascending if the reversed option is set to true

Property

Type

Sorters

datapoint*

integer($int32);

Datapoint index in datapoint array (0-based)

reversed

boolean

Determines if the sorting result should be regular (descending) or reversed (ascending). False by default

The value format is:

"sorters": [
    {
        "datapoint": 7,
        "reversed": false
    }
],

outputs

Array

Datapoint indices to include in the output

The value format is:

"outputs": [
    {
        "datapoint": 0
    },
    {
        "datapoint": 1
    }
]

options

Array

Additional query options. Currently, Scanner API supports only one option - snapshotSize integer($int32), which specifies the maximum results to be returned

The value format is:

"options": {
    "snapshotSize": 1000
}

ScanQuery.Datapoints

Each datapoint consists of two parts, a datapoint name (name) and a datapoint expression (expr). dxFeed Scanner supports 150+ pre-built datapoints; here is the full list. You can use dxScript expressions to build custom datapoints using functions and pre-built datapoints.

Please routinely check the supported pre-built datapoints list here and the /docs/datapoints/ endpoint since new Scanner releases sometimes result in datapoint updates.

Datapoint parameters

The dxFeed Scanner technical indicators support parametrized calculation. A user can specify candleCount, candlePeriod, timePeriod and session parameters to display its calculation.

  • candlePeriod parameter defines candle type for calculations using:

    • 1m - for 1-minute candle

    • 2m - for 2-minute candle

    • 3m - for 3-minute candle

    • 4m - for 4-minute candles

    • 5m - for 5-minute candles

    • 10m - for 10-minute candle

    • 15m - for 15-minute candle

    • 30m - for 30-minute candle

    • 1h - for 1-hour candle

    • 2h - for 2-hour candle

    • 4h - for 4-hour candle

    • 1d - for 1-day candle

    • 1w - for 1-week candle

    • 1mo - for 1-month candle

    • 1y - for 1-year candle

  • candleCount parameter defines the exact candle number used for calculation.

  • session parameter defines the session types used for calculations:

    • all (default if the parameter is not specified) - regular, pre-market, and post-market

    • regular - only regular

  • timePeriod parameter defines the calendar period for the candles' number restrictions:

    • 1d - all fully finished candles in the defined number of calendar days will be taken, any number of calendar days can be defined

    • 1w - all fully finished candles in the defined number of calendar weeks will be taken, any number of weeks can be defined

    • 1mo - all fully finished candles in the defined number of calendar months will be taken, any number of months can be defined

    • 1y - all fully finished candles in the defined number of calendar years will be taken, any number of years can be defined

    • ytd - all fully finished candles between the start of the year and the requested date will be taken

Example. Ratio between ATM IV and statistical volatility for a month

To get the ratio between ATM Implied Volatility and statistical volatility for one month, use the following datapoint:

{
    "name": "RATIO_IV_TO_SV_1_MONTH",
    "expr": "underlying.atmIv30Day / underlying.statVol1Month(session=\"regular\")"
}

Example. Total call volume ratio to the average for 10 days

To calculate the options session call volume ratio to the 10 days average, use the following datapoint:

{
    "name": "VOLUME_TOTAL_CALL_RATIO",
    "expr": "underlying.optionsCallVolume(session=\"regular\") / underlying.optionsCallVolumeAvg10Day(session=\"regular\")"
}

ScanQuery.Selectors

Note

This section is obsolete. Please refer to it for backward compatibility only. Please refer to Appendix B, Migrate selectors to filters for details on how to implement functionality using filters.

This function is deprecated, relevant features shall be now implemented with ScanQuery.Filters functionality. See also Appendix A, Special functions.

Scanner API optimized the selectors to narrow down the set of symbols on which the search is performed. You can use type (e.g. OPTION, ETF, STOCK), symbol (e.g. AAPL, FB, .AMZN190628C1300, etc.), and underlying for derivatives (AAPL, FB) to limit the set of instruments you work with.

Property

Type

Description

Expected values

select*

string

Selector type

  • type

  • symbol

  • underlying

values*

array

Selector values to apply

Depending on selector type and the symbol universe dxFeed Scanner works with

Example. Selecting options only

"selectors": [
    {
        "select": "type",
        "values": [
            "OPTION"
        ]
    }
]

ScanQuery.Filters

Filters are search criteria built on datapoints. In each filter, you can define a datapoint and criteria (alternatives property) that the datapoint shall match.

  • Combine several alternatives using OR operation for the selected datapoint to meet any alternative

  • Filters themselves are combined using AND operation for the selected symbol datapoint to meet all alternatives.

Property

Type

Description

datapoint*

integer($int32)

Datapoint index in datapoint array (0-based). If this is the only provided filter property, then the specified datapoint must have a boolean type

not

Boolean

Whether the filter should be negated. False by default

alternatives

Array

Alternatives for the filtered datapoint:

predicate*

Predicate name. The following values are allowed:

== - equality, requires one argument, works for all primitive and enum types

< - checks if the datapoint value is less than the given single numeric argument

<= - checks if the datapoint value is less than or equal to the given single numeric argument

> - checks if the datapoint value is greater than the given single numeric argument

>= - checks if the datapoint value is greater than or equal to the given single numeric argument

[] - checks if the datapoint value is between two numeric arguments (inclusive)

anyOf - checks if the datapoint value equals to any of the arguments

args*

One or more predicate arguments

not

Whether the alternative should be negated. Boolean. False by default

Example. Filtering a datapoint to be greater than 1.5

"filters": [
    {
        "datapoint": 7,
        "alternatives": [
            {
                "predicate": ">=",
                "args": [
                    1.5
                ]
            }
        ]
    }
]

Appendix A. Special functions

Relative Options

When running requests in the OPTION category, it is possible to access any neighboring datapoint option by strike and with the same or opposite type (call vs put). There is a special function to specify how to choose such a relative option.

Parameter

Type

Default Value

Description

strikeIntervals

number

0

positive or negative integer:

0 - same strike

+1 - option with the closest strike that is greater

-1 - option with the closest strike that is less

+n - n'th strike in the greater prices' direction

-n - n'th strike in the lower prices' direction

isOpposite

boolean

false

false call => call, put => put

true call => put, put => call

Example. Search for a tradeable vertical spread

A vertical spread is an options trading strategy that involves the simultaneous buying and selling of options of the same type (i.e., either puts or calls) and expiry, but at different strike prices. The vertical term comes from the strike prices' position. Traders will use a vertical spread when they expect a moderate move in the underlying asset's price. Vertical spreads are mainly directional plays and can be tailored to reflect the trader's view, bearish or bullish, on the underlying asset.

Consider we want to find a two strikes wide vertical spread with both legs tradable and delta at around .45, where tradable stands for leg open interest being greater than 100. We want these spreads to be sorted by spread price, that is the first leg's price minus the second one's price. For that query, we would format the request as follows:

{
    "instrumentCategory": "OPTION",
    "datapoints": [
        {
            "expr": "underlying.price"
        },
        {
            "expr": "strikePrice"
        },
        {
            "name": "secondLegStrikePrice",
            "expr": "strikePrice(option(strikeIntervals=2))"
        },
        {
            "name": "spreadPrice",
            "expr": "price-price(option(strikeIntervals=2))"
        },
        {
            "expr": "greeks.delta"
        },
        {
            "expr": "openInterest"
        },
        {
            "name": "secondLegDelta",
            "expr": "greeks.delta(option(strikeIntervals=2))"
        },
        {
            "name": "secondLegOpenInterest",
            "expr": "openInterest(option(strikeIntervals=2))"
        }
    ],
    "filters": [
        {
            "datapoint": 4,
            "alternatives": [
                {
                    "predicate": "[]",
                    "args": [
                        "0.43",
                        "0.45"
                    ]
                }
            ]
        },
        {
            "datapoint": 6,
            "alternatives": [
                {
                    "predicate": "[]",
                    "args": [
                        "0.43",
                        "0.45"
                    ]
                }
            ]
        },
        {
            "datapoint": 5,
            "alternatives": [
                {
                    "predicate": ">",
                    "args": [
                        "100"
                    ]
                }
            ]
        },
        {
            "datapoint": 7,
            "alternatives": [
                {
                    "predicate": ">",
                    "args": [
                        "100"
                    ]
                }
            ]
        }
    ],
    "sorters": [
        {
            "datapoint": 3,
            "reversed": true
        }
    ],
    "options": {
        "snapshotSize": 100,
        "allAsOutputs": true
    }
}

And the result might look like:

symbol

underlying.price

strikePrice

secondLegStrikePrice

spreadPrice

greeks.delta

openInterest

secondLegDelta

secondLegOpenInterest

.SPY220617C476

464.7

476

478

0.65

0.446

389

0.431176

1241

.SPX220218C4710

4649.27

4710

4720

0.96

0.445457

235

0.434049

163

.QQQ220617C406

391.52

406

408

2.34

0.444805

508

0.432029

838

.SPXW220121C4700

4649.27

4700

4710

6.5

0.445454

786

0.430869

273

.SPX220121C4700

4649.27

4700

4710

8.09

0.444977

17749

0.430869

273

.TSLA240119C1900

1063.38

1900

1950

9.49

0.440436

1105

0.430127

827

.SPXW220218C4710

4649.27

4710

4720

33.36

0.445756

149

0.434049

163

Scanner results filtering by index constituent symbols

It's possible to narrow down the Scanner results to a list of symbols constituting a public index, like the S&P 500, Russel 2000, etc.

Use a special inList predicate to achieve such filtering. This predicate accepts one or many index names as arguments and narrows down the result set to the list of symbols from any index. For example, the following request returns only symbols that are part of the S&P 500, Russel 2000, or both indices:

{
  "instrumentCategory": "UNDERLYING",
  "datapoints": [
    {
      "expr": "symbol"
    }
  ],
  "filters": [
    {
      "datapoint": 0,
      "alternatives": [
        {
          "predicate": "inList",
          "args": ["SP500", "Russell2000"]
        }
      ]
    }
  ]
}

To retrieve a full list of supported indices, use the IPF request with ipf?help=lists. For a list of index constituent symbols, use IPF request with ipf?lists=LISTNAME syntax. For example, ipf?lists=SP500 returns symbols for the S&P 500 index constituents.

Note

Use demo/demo credentials to check IPF examples.

Appendix B. Migrate from selectors to filters

The selector mechanism is deprecated in the Scanner HTTP API and will be removed in the near future.

The original selectors' purpose was to allow filtering specific datapoints using a given list of values. This was not initially possible to do using regular filters. Now, though filters support a predicate anyOf that allows the selectors' functionality replication.

Mapping Between Selectors and Expressions

Selector name

Datapoint expression

symbol

symbol

type

type

underlying

underlying.symbol

Examples

Request with selectors

The following is a request example with selectors in the body:

{
    "instrumentCategory": "UNDERLYING",
    "selectors": [
        {
            "select": "type",
            "values": [
                "STOCK",
                "ETF"
            ]
        }
    ],
    "datapoints": [
        {
            "expr": "price"
        }
    ],
    "filters": [
        {
            "datapoint": 0,
            "alternatives": [
                {
                    "predicate": ">",
                    "args": [
                        "100"
                    ]
                }
            ]
        }
   ],
    "outputs": [
        {
            "datapoint": 0
        }
    ]
}

Refactored request without selectors

To archive the same result using a filter, we need to remove the selectors' field from the request and instead add a datapoint and a corresponding filter.

The following is an updated request example without selectors:

{
    "instrumentCategory": "UNDERLYING",
    "datapoints": [
        {
            "expr": "price"
        },
        {
            "expr": "type"
        }
    ],
    "filters": [
        {
            "datapoint": 0,
            "alternatives": [
                {
                    "predicate": ">",
                    "args": [
                        "100"
                    ]
                }
            ]
        },
        {
            "datapoint": 1,
            "alternatives": [
                {
                    "predicate": "anyOf",
                    "args": [
                        "STOCK",
                        "ETF"
                    ]
                }
            ]
        }
    ],
    "outputs": [
        {
            "datapoint": 0
        }
    ]
}

Several things changed:

  • selectors' field was removed from the body

  • a new entry was added to the datapoints field; this datapoint uses the values of the select as an expr

  • a new entry was added to the filters field; the new filter refers to the new datapoint and uses the anyOf predicate

The exact same migration procedure can be applied for other selectors, mapping the old select to the expr specified in the table above.

If the same request has multiple selectors, you need to create a separate datapoint and filter for each one.

Note

Unless the user has explicitly specified they want to see the new datapoint and filter in the results, we only add it to the request and not into the outputs section.

Note

You should never include datapoints with symbol expression to the outputs. The actual symbols are always available in the response as JSON object keys. Requesting them additionally in the outputs adds unneeded traffic and processing.

Samples

Request

{
	"instrumentCategory": "OPTION",
	"datapoints": [
		{
			"name": "SYMBOL",
			"expr": "symbol"
		},
		{
			"name": "UNDERLIER_SYMBOL",
			"expr": "underlying.symbol"
		},
		{
			"name": "MARKET_EXCHANGE",
			"expr": "officialPlaceOfListing"
		},
		{
			"name": "UNDERLIER_TYPE",
			"expr": "underlying.type"
		},
		{
			"name": "IMPLIED_VOLATILITY_30_DAY",
			"expr": "underlying.atmIv30Day"
		},
		{
			"name": "LAST_PRICE",
			"expr": "underlying.price(session=\"regular\")"
		},
		{
			"name": "OPEN_INTEREST_OPTION",
			"expr": "openInterest"
		},
		{
			"name": "RATIO_IV_TO_SV_1_MONTH",
			"expr": "underlying.atmIv30DayPosInRange / underlying.statVol1Month(session=\"regular\")"
		},
		{
			"name": "STATISTICAL_VOLATILITY_1_MONTH",
			"expr": "underlying.statVol1Month(session=\"regular\")"
		},
		{
			"name": "VOLUME",
			"expr": "underlying.dayVolume(session=\"regular\")"
		},
		{
			"name": "VOLUME_OPTION",
			"expr": "dayVolume"
		},
		{
			"name": "VOLUME_TOTAL_OPTION_10_DAY_AVERAGE",
			"expr": "underlying.optionsTotalVolumeAvg10Day"
		},
		{
			"name": "VOLUME_TOTAL_CALL_RATIO",
			"expr": "underlying.optionsCallVolume(session=\"regular\") / underlying.optionsCallVolumeAvg10Day(session=\"regular\")"
		}
	],
	"outputs": [
		{
			"datapoint": 0
		},
		{
			"datapoint": 1
		},
		{
			"datapoint": 2
		},
		{
			"datapoint": 4
		},
		{
			"datapoint": 5
		},
		{
			"datapoint": 6
		},
		{
			"datapoint": 7
		},
		{
			"datapoint": 8
		},
		{
			"datapoint": 9
		},
		{
			"datapoint": 10
		},
		{
			"datapoint": 11
		},
		{
			"datapoint": 12
		}
	],
	"filters": [
		{
			"datapoint": 3,
			"alternatives": [
				{
					"predicate": "==",
					"args": [
						"STOCK"
					]
				}
			]
		},
		{
			"datapoint": 6,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						500
					]
				}
			]
		},
		{
			"datapoint": 7,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						1.5
					]
				}
			]
		},
		{
			"datapoint": 10,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						100
					]
				}
			]
		},
		{
			"datapoint": 11,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						1000
					]
				}
			]
		}
	],
	"sorters": [
		{
			"datapoint": 7,
			"reversed": false
		}
	],
	"options": {
		"snapshotSize": 1000
	}
}
{
	"instrumentCategory": "OPTION",
	"datapoints": [
		{
			"name": "SYMBOL",
			"expr": "symbol"
		},
		{
			"name": "UNDERLIER_SYMBOL",
			"expr": "underlying.symbol"
		},
		{
			"name": "MARKET_EXCHANGE",
			"expr": "officialPlaceOfListing"
		},
		{
			"name": "UNDERLIER_TYPE",
			"expr": "underlying.type"
		},
		{
			"name": "IMPLIED_VOLATILITY_30_DAY",
			"expr": "underlying.atmIv30Day"
		},
		{
			"name": "LAST_PRICE",
			"expr": "underlying.price(session=\"regular\")"
		},
		{
			"name": "OPEN_INTEREST_OPTION",
			"expr": "openInterest"
		},
		{
			"name": "RATIO_IV_TO_SV_1_MONTH",
			"expr": "underlying.atmIv30DayPosInRange / underlying.statVol1Month(session=\"regular\")"
		},
		{
			"name": "STATISTICAL_VOLATILITY_1_MONTH",
			"expr": "underlying.statVol1Month(session=\"regular\")"
		},
		{
			"name": "VOLUME",
			"expr": "underlying.dayVolume(session=\"regular\")"
		},
		{
			"name": "VOLUME_OPTION",
			"expr": "dayVolume"
		},
		{
			"name": "VOLUME_TOTAL_OPTION_10_DAY_AVERAGE",
			"expr": "underlying.optionsTotalVolumeAvg10Day"
		},
		{
			"name": "VOLUME_TOTAL_CALL_RATIO",
			"expr": "underlying.optionsCallVolume(session=\"regular\") / underlying.optionsCallVolumeAvg10Day(session=\"regular\")"
		}
	],
	"outputs": [
		{
			"datapoint": 0
		},
		{
			"datapoint": 1
		},
		{
			"datapoint": 2
		},
		{
			"datapoint": 4
		},
		{
			"datapoint": 5
		},
		{
			"datapoint": 6
		},
		{
			"datapoint": 7
		},
		{
			"datapoint": 8
		},
		{
			"datapoint": 9
		},
		{
			"datapoint": 10
		},
		{
			"datapoint": 11
		},
		{
			"datapoint": 12
		}
	],
	"selectors": [
		{
			"select": "type",
			"values": [
				"OPTION"
			]
		}
	],
	"filters": [
		{
			"datapoint": 3,
			"alternatives": [
				{
					"predicate": "==",
					"args": [
						"STOCK"
					]
				}
			]
		},
		{
			"datapoint": 6,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						500
					]
				}
			]
		},
		{
			"datapoint": 7,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						1.5
					]
				}
			]
		},
		{
			"datapoint": 10,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						100
					]
				}
			]
		},
		{
			"datapoint": 11,
			"alternatives": [
				{
					"predicate": ">=",
					"args": [
						1000
					]
				}
			]
		}
	],
	"sorters": [
		{
			"datapoint": 7,
			"reversed": false
		}
	],
	"options": {
		"snapshotSize": 1000
	}
}

Response, snapshot

{
    "outputNames": [
        "SYMBOL",
        "UNDERLIER_SYMBOL",
        "MARKET_EXCHANGE",
        "IMPLIED_VOLATILITY_30_DAY",
        "LAST_PRICE",
        "OPEN_INTEREST_OPTION",
        "RATIO_IV_TO_SV_1_MONTH",
        "STATISTICAL_VOLATILITY_1_MONTH",
        "VOLUME",
        "VOLUME_OPTION",
        "VOLUME_TOTAL_OPTION_10_DAY_AVERAGE",
        "VOLUME_TOTAL_CALL_RATIO"
    ],
    "entries": [
        {
            "symbol": ".LLY210319C200",
            "outputs": [
                ".LLY210319C200",
                "LLY",
                "BATO",
                0.4582537027697168,
                208.15,
                2060,
                5.2591509629209,
                0.1888967835442762,
                2990271,
                709,
                19432.828571428574,
                1.8236217044220673
            ]
        },
        {
            "symbol": ".LLY210319C202.5",
            "outputs": [
                ".LLY210319C202.5",
                "LLY",
                "BATO",
                0.4582537027697168,
                208.15,
                765,
                5.2591509629209,
                0.1888967835442762,
                2990271,
                524,
                19432.828571428574,
                1.8236217044220673
            ]
        }
    ]
}