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.), For detailed field definitions, see Filter Field Description. |
| AccumulateField | Cumulative indicator filters, including cumulative price change, Supported accumulation periods include, but are not limited to: |
| FinancialField | Financial statement–based indicator filters, including gross profit, Financial indicators currently support TTM (Last Twelve Months) |
| MultiTagField | Multi-label association filter conditions, based on industry, concept, and historical price characteristics, such as:
|
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_alternativefrom 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:
| Field | Type | Description |
|---|---|---|
| market | str | Market code (e.g., US for U.S. stocks) |
| multi_tag_field | str | Multi‑tag field type (e.g., industry or concept) |
| tag_list | list[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"
}
]
}
]Updated 5 months ago