Stock Screener

Multi‑tag field type (e.g., industry or concept).## market_scanner Stock Screener

QuoteClient.market_scanner(self, market: Optional[Union[Market, str]] = Market.US, filters: Optional[List[StockFilter]] = None, sort_field_data: Optional[SortFilterData] = None, page: Optional[int] = 0, page_size: Optional[int] = 100, cursor_id: Optional[str] = None)

Description

Scan the entire market using different technical indicator conditions to filter out a list of securities that meet specific investment needs.

Technical indicator conditions include the following categories: basic indicators, cumulative indicators, financial indicators, and multi-label indicators. Please refer to the explanations below for the details on specific parameters.

Parameters

Parameter

Type

Required

Description

market

tigeropen.common.consts.Market

Yes

Market identifier. Supported values include:
US — U.S. stocks

filters

list[StockFilter]

Yes

List of filters, for more details see StockFilter Parameters

sort_field_data

tigeropen.quote.domain.filter.SortFilterData

No

Sort field object with the two following attributes

∟ field

enum

No

Sort field, must be an enum value from tigeropen.common.consts.filter_fields, such as StockField or AccumulateField

∟ sort_dir

tigeropen.common.consts.SortDirection

No

Sort order. Supported values: none, ascending, descending

page

int

No

Current page number, starting from 0. Not recommended for use; please use cursor_id instead.

cursor_id

str

No

Cursor ID for cursor-based pagination. Clients should pass this value when requesting the next page. For the first request, pass None

page_size

int

No

Number of data items returned per page. Maximum supported value: 200

StockFilter Parameters:

Parameter

Type

Required

Description

field

tigeropen.common.consts.filter_fields.FilterField

Yes

This enum defines four types of fields; see detailed explanations below

filter_min

float

No

Lower bound of the filter range (inclusive). If not provided, the lower bound defaults to -∞. For percentile-based filters, do not include the percent sign. Example: for 10%, use the value 10

filter_max

float

No

Upper bound of the filter range (inclusive). If not provided, the upper bound defaults to +∞

is_no_filter

bool

No

Indicates whether this filter is disabled. If true, the filter will not be applied.

accumulate_period

tigeropen.common.consts.filter_fields.AccumulatePeriod

No

Accumulation period enum. Only required when the field is AccumulateField

financial_period

tigeropen.common.consts.filter_fields.FinancialPeriod

No

Financial period enum. Only required when the field is FinancialField

tag_list

list[int,str]

No

List of tag values to filter on. Only required when the field is MultiTagField.

StockFilter field has the following enum types (import path: tigeropen.common.consts.filter_fields)

Type

Description

StockField

Simple technical indicator filters, including price (OHLC, latest price, etc.), trading volume, share capital, market value, price change, P/E ratio, turnover rate, and other related factors.

For detailed field definitions, see Filter Field Description.

AccumulateField

Cumulative indicator filters, including cumulative price change, asset growth rate, net profit growth rate, earnings per share, net profit, operating profit, operating income, ROE (return on equity), operating cash flow, debt-to-asset ratio, and similar metrics.

Supported accumulation periods include, but are not limited to: last 5 minutes, last 5 days, 10 days, 20 days, half year, one year, two years, five years, Q1 report, Q3 report, and interim report. For detailed field definitions, see Filter Field Description

FinancialField

Financial statement–based indicator filters, including gross profit, net profit margin, total debt/shareholders’ equity, total debt, total assets, current ratio, return on assets, net profit, operating cash flow, and total assets.

Financial indicators currently support TTM (Last Twelve Months) and annual report–based queries only. For detailed field definitions, see Filter Field Description

MultiTagField

Multi-label association filter conditions, based on industry, concept, and historical price characteristics, such as:

  • Historical price highs (current price vs. historical prices)
  • 52-week highs (current price vs. last 52 weeks)
  • OTC trading support
  • Options trading support
  • Stock type (e.g., ETF)
  • Whether an IPO has a broken issue price

For detailed field definitions, see Filter Field Description

Note: The currency used for price-related filter parameters is determined by the market of the underlying asset. For example, U.S. stocks would use USD

Returns

tigeropen.quote.domain.filter.ScannerResult

Class structure is as follows:

class ScannerResult:
    def __init__(self, page, page_size, total_page, total_count, items, cursor_id):
        # Current page number, starting from 0
        self.page = page
        # Total number of pages
        self.total_page = total_page
        # Total number of data items
        self.total_count = total_count
        # Page size
        self.page_size = page_size
        # Next page cursor ID
        self.cursor_id = cursor_id
        # Result data list
        self.items: ScannerResultItem = list()
        # Summary of filtered stock symbol list
        self.symbols = list()

# Each item in items is:
class ScannerResultItem:
    def __init__(self, symbol, market, base_data_list=None, accumulate_data_list=None, financial_data_list=None,
                 multi_tag_data_list=None):
        self.symbol = symbol
        self.market = market
        self.field_data = dict()

# You can use filter as key to get the corresponding filter field value, see example below

Example

import time
from datetime import datetime
from tigeropen.quote.quote_client import QuoteClient
from tigeropen.tiger_open_config import get_client_config
from tigeropen.common.consts import TradingSession, Market
from tigeropen.quote.domain.filter import OptionFilter, StockFilter, SortFilterData
from tigeropen.common.consts.filter_fields import StockField, AccumulateField, FinancialField, MultiTagField, \
    FinancialPeriod, AccumulatePeriod

from tigeropen.tiger_open_config import TigerOpenClientConfig
client_config = TigerOpenClientConfig(props_path='/path/to/your/properties/file/')

quote_client = QuoteClient(client_config)

def test_market_scanner():
    # Stock basic data filter (is_no_filter=True means this filter is not enabled)
    base_filter1 = StockFilter(StockField.FloatShare, filter_min=1e7, filter_max=1e13, is_no_filter=True)
    base_filter2 = StockFilter(StockField.MarketValue, filter_min=1e8, filter_max=1e14, is_no_filter=False)
    # Filter by earnings date
    base_filter3 = StockFilter(StockField.EarningDate, filter_min=int(datetime.strptime('2021-01-01', '%Y-%m-%d').timestamp() * 1000),
                                   filter_max=int(datetime.strptime('2023-12-31', '%Y-%m-%d').timestamp() * 1000)
                                   , is_no_filter=False)
    # Periodic cumulative data filter
    accumulate_filter = StockFilter(AccumulateField.ChangeRate, filter_min=0.01, filter_max=1, is_no_filter=False,
                                    accumulate_period=AccumulatePeriod.Last_Year)
    # Financial data filter
    financial_filter = StockFilter(FinancialField.LYR_PE, filter_min=1, filter_max=100, is_no_filter=False,
                                   financial_period=FinancialPeriod.LTM)
    # Multi-tag data filter, need to get tag_list first. If there are values, pass them according to the situation. If no values, don't pass tag_list parameter; For boolean fields, tag_list is generally empty and no value needs to be passed
    tags = quote_client.get_market_scanner_tags(market=Market.US, tag_fields=[MultiTagField.OptionsAvailable])
    if not tags:
        tag_list = []
    else:
        # Need to replace with the desired tag based on actual situation, e.g., when field is MultiTagField.Industry, tag_list = ['BK4209']
        tag_list = ['BK4209']
    multi_tag_filter = StockFilter(MultiTagField.isOTC, tag_list=tag_list)


    # Sort field
    sort_field_data = SortFilterData(StockField.FloatShare, sort_dir=SortDirection.ASC)

    cursor_id = None
    page_size = 50
    # Whether it's the last page of data
    is_last_page = False
    # Symbol list after filtering
    scanner_result_symbols = set()

    while not is_last_page:
        # Put the filters you want to use in the filters parameter
        result = quote_client.market_scanner(market=Market.US,
                                             filters=[base_filter1, base_filter2, 
                                                      # base_filter3,
                                                      accumulate_filter,
                                                      financial_filter,
                                                      multi_tag_filter],
                                             sort_field_data=sort_field_data,
                                             cursor_id=cursor_id,
                                             page_size=page_size)
        print(result)
        if result.total_page:
            for item in result.items:
                # item type is ScannerResultItem 
                symbol = item.symbol
                market = item.market
                # You can get the value of a certain filter field in dictionary form
                base_filter1_value = item[base_filter1]
                accumulate_filter_value = item[accumulate_filter]
                print(
                    f'page:{result.page}, symbol:{symbol}, base_filter1 value:{base_filter1_value}, accumulate_filter value:{accumulate_filter_value}')
            print(f'current page symbols:{result.symbols}')
            scanner_result_symbols.update(result.symbols)
        time.sleep(10)
        # Handle pagination
        if not result.cursor_id:
            is_last_page = True
        else:
            cursor_id = result.cursor_id

    print(f'scanned symbols:{scanner_result_symbols}')

Return Example

ScannerResult({'page': 0, 'total_page': 208, 'total_count': 1040, 'page_size': 5, 
    'cursor_id': 'xxxxxx',
  'items': [
    ScannerResultItem({'symbol': 'DNP', 'market': 'US', 
        'field_data': {
          <StockField.FloatShare: 13>: 0.0, 
          <StockField.MarketValue: 17>: 3855828898.39, 
          <AccumulateField.ChangeRate: 1>: 0.043925, 
          <FinancialField.LYR_PE: 45>: 7.359675, 
          <MultiTagField.isOTC: 3>: '0'}}), 
    ScannerResultItem({'symbol': 'FEN', 'market': 'US', 
        'field_data': {
        <StockField.FloatShare: 13>: 0.0, 
        <StockField.MarketValue: 17>: 278571284.64, 
        <AccumulateField.ChangeRate: 1>: 0.063893, 
        <FinancialField.LYR_PE: 45>: 6.45728, 
        <MultiTagField.isOTC: 3>: '0'}}), 
    ScannerResultItem({'symbol': 'FDUS', 'market': 'US', 
        'field_data': {
            <StockField.FloatShare: 13>: 0.0, 
            <StockField.MarketValue: 17>: 462844356.0, 
            <AccumulateField.ChangeRate: 1>: 0.079202, 
            <FinancialField.LYR_PE: 45>: 3.986464, 
            <MultiTagField.isOTC: 3>: '0'}}), 
    ScannerResultItem({'symbol': 'KYN', 'market': 'US', 
        'field_data': {
            <StockField.FloatShare: 13>: 0.0, 
            <StockField.MarketValue: 17>: 1181621680.4,
             <AccumulateField.ChangeRate: 1>: 0.122898, 
             <FinancialField.LYR_PE: 45>: 3.268946, 
             <MultiTagField.isOTC: 3>: '0'}}),
    ScannerResultItem({'symbol': 'TYG', 'market': 'US', 
        'field_data': {
            <StockField.FloatShare: 13>: 0.0, 
            <StockField.MarketValue: 17>: 381692896.0,
            <AccumulateField.ChangeRate: 1>: 0.180812, 
            <FinancialField.LYR_PE: 45>: 2.853998, 
            <MultiTagField.isOTC: 3>: '0'}})], 
  'symbols': ['FEN', 'DNP', 'FDUS', 'KYN', 'TYG']})

Example 1 Select stocks with a dividend yield above 5% and a revenue compound annual growth rate over the past three years greater than 10%.

from tigeropen.quote.quote_client import QuoteClient
from tigeropen.common.consts import TradingSession
from tigeropen.quote.domain.filter import OptionFilter, StockFilter, SortFilterData
from tigeropen.common.consts.filter_fields import StockField, AccumulateField, FinancialField, MultiTagField, \
    FinancialPeriod, AccumulatePeriod

from tigeropen.tiger_open_config import TigerOpenClientConfig
client_config = TigerOpenClientConfig(props_path='/path/to/your/properties/file/')

quote_client = QuoteClient(client_config)

def test_market_scanner1():

    # Dividend yield greater than 5%
    base_filter = StockFilter(StockField.DivideRate, filter_min=0.05)
    # Total revenue 3-year growth rate or revenue 3-year compound annual growth rate
    financial_filter = StockFilter(FinancialField.TotalRevenues3YrCagr, filter_min=0.1)
    
    cursor_id = None
    page_size = 50
    # Whether it's the last page of data
    is_last_page = False
    # Symbol list after filtering
    scanner_result_symbols = set()

    while not is_last_page:
        # Put the filters you want to use in the filters parameter
        result = quote_client.market_scanner(market=Market.US,
                                             filters=[
                                                 base_filter,
                                                 financial_filter,
                                             ],
                                             cursor_id=cursor_id,
                                             page_size=page_size)
        print(result)
        if result.total_page:
            for item in result.items:
                symbol = item.symbol
                market = item.market
                # You can get the value of a certain filter field in dictionary form
                base_filter_value = item[base_filter]
                financial_filter_value = item[financial_filter]
                print(
                    f'page:{result.page}, symbol:{symbol}, base_filter value:{base_filter_value}, financial_filter value:{financial_filter_value}')
            print(f'current page symbols:{result.symbols}')
            scanner_result_symbols.update(result.symbols)
        time.sleep(10)
        # Handle pagination
        if result.cursor_id is None:
            is_last_page = True
        else:
            cursor_id = result.cursor_id

    print(f'scanned symbols:{scanner_result_symbols}')

Example 2 Filter by ETF type

Optional ETF type tag values in tag_list

Hot ETFs: package_us_v1_etf_hot
Bank ETF: package_us_v1_etf_bank
Bond ETF: package_us_v1_etf_bond
Buffer ETF: package_us_v1_etf_buffer
Broad Index ETF: package_us_v1_etf_index
Leveraged & Inverse ETF: package_us_v1_etf_leverage
Sector ETF: package_us_v1_etf_sector
Single Stock Leveraged ETF: package_us_v1_etf_single_stock
Market Cap ETF: package_us_v1_etf_market_cap
Thematic ETF: package_us_v1_etf_thematic
International ETF: package_us_v1_etf_international
Growth & Value ETF: package_us_v1_etf_growth
Commodity ETF: package_us_v1_etf_commodity
ARK ETF: package_us_v1_etf_ark
Volatility ETF: package_us_v1_etf_volatility
Currency ETF: package_us_v1_etf_currency
Alternative Investment ETF: package_us_v1_etf_alternative
from tigeropen.quote.quote_client import QuoteClient
from tigeropen.tiger_open_config import get_client_config
from tigeropen.common.consts import Market
from tigeropen.quote.domain.filter import StockFilter
from tigeropen.common.consts.filter_fields import MultiTagField

client_config = get_client_config(private_key_path='private_key_path', tiger_id='your tiger id', account='your account')
quote_client = QuoteClient(client_config)

def test_market_scanner_etf():
    # Filter by ETF type, here we filter growth and alternative investment ETFs
    multi_tag_filter_etftype = StockFilter(MultiTagField.ETF_TYPE, tag_list=["package_us_v1_etf_growth", "package_us_v1_etf_alternative"])
    
    cursor_id = None
    page_size = 50
    # Whether it's the last page of data
    is_last_page = False
    # Symbol list after filtering
    scanner_result_symbols = set()

    while not is_last_page:
        result = quote_client.market_scanner(market=Market.US,
                                          filters=[multi_tag_filter_etftype],
                                          cursor_id=cursor_id,
                                          page_size=page_size)
        
        if result.total_page:
            for item in result.items:
                symbol = item.symbol
                market = item.market
                etf_type_value = item[multi_tag_filter_etftype]
                print(f'page:{result.page}, symbol:{symbol}, etf_type:{etf_type_value}')
            print(f'current page symbols:{result.symbols}')
            scanner_result_symbols.update(result.symbols)
            
        time.sleep(10)
        # Handle pagination
        if result.cursor_id is None:
            is_last_page = True
        else:
            cursor_id = result.cursor_id

    print(f'scanned symbols:{scanner_result_symbols}')

get_market_scanner_tags

QuoteClient.get_market_scanner_tags(self, market=Market.US, tag_fields=None)

Description

Get tag values for multi-label association filter fields. Currently only supports getting industry and concept tag sets.

Parameters

Parameter

Type

Required

Description

market

tigeropen.common.consts.Market

Yes

Market identifier. Supported values include:
US — U.S. stocks

tag_fields

list[tigeropen.common.consts.filter_fields.MultiTagField]

Yes

List of supported multi‑tag field enum values Supported values include:
MultiTagField.Industry MultiTagField.Concept

Returns

list. Each item as follows:

FieldTypeDescription
marketstrMarket code (e.g., US for U.S. stocks)
multi_tag_fieldstrMulti‑tag field type (e.g., industry or concept)
tag_listlist[str]Set of tags that can be used to filter multi-tag fields

Example

from tigeropen.quote.quote_client import QuoteClient
from tigeropen.common.consts import TradingSession, Market
from tigeropen.common.consts.filter_fields import MultiTagField

from tigeropen.tiger_open_config import TigerOpenClientConfig
client_config = TigerOpenClientConfig(props_path='/path/to/your/properties/file/')

quote_client = QuoteClient(client_config)

field_list = [ MultiTagField.Concept, MultiTagField.Industry]
result = quote_client.get_market_scanner_tags(market=Market.US, fields=field_list)
print(result)

Return Example

[
    {
        "market": "US",
        "multi_tag_field": "MultiTagField_Concept",
        "tag_list": [
            {
                "tag": "BK4565",
                "value": "NFT Concept"
            },
            {
                "tag": "BK4564",
                "value": "Space Concept"
            },
            {
                "tag": "BK4567",
                "value": "ESG Concept"
            },
            {
                "tag": "BK4566",
                "value": "Capital Group"
            },
            {
                "tag": "BK4568",
                "value": "US Anti-Pandemic Concept"
            },
            {
                "tag": "BK4561",
                "value": "Soros Holdings"
            },
            {
                "tag": "BK4560",
                "value": "Cybersecurity Concept"
            }
        ]
    }
]