Stock Screener
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 help you 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 specific parameter meanings.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| market | tigeropen.common.consts.Market | Yes | US for US stocks, SG for Singapore stocks, HK for Hong Kong stocks |
| filters | list[StockFilter] | Yes | List of filters, four categories in total, see explanation below |
| sort_field_data | tigeropen.quote.domain.filter.SortFilterData | No | Sort field object with main attributes as shown below |
| ∟ field | enum | No | Sort field, field enum from tigeropen.common.consts.filter_fields, such as StockField, AccumulateField |
| ∟ sort_dir | tigeropen.common.consts.SortDirection | No | Sort direction, including: no sort, ascending, descending |
| page | int | No | Current page number (starting from 0). Not recommended, please use cursor_id |
| cursor_id | str | No | Cursor ID for cursor-based pagination queries. Clients should pass this value when getting the next page, can pass None for the first query |
| page_size | int | No | Number of data items returned per page, maximum supported configuration: 200 |
StockFilter parameter explanation:
| Parameter | Type | Required | Description |
|---|---|---|---|
| field | tigeropen.common.consts.filter_fields.FilterField | Yes | Four types of fields, see explanation below |
| filter_min | float | No | Lower limit of range (closed interval), not passing means lower limit is -∞. For percentiles, don't add %, e.g., for 10%, just use value 10 |
| filter_max | float | No | Upper limit of range (closed interval), not passing means upper limit is +∞ |
| is_no_filter | bool | No | Whether to disable this filter. If True, this filter will not take effect |
| accumulate_period | tigeropen.common.consts.filter_fields.AccumulatePeriod | No | Accumulation period enum, only needed when field is AccumulateField |
| financial_period | tigeropen.common.consts.filter_fields.FinancialPeriod | No | Financial period enum, only needed when field is FinancialField |
| tag_list | list[int,str] | No | Tag list, only needed when field is MultiTagField |
StockFilter field has the following enum types (import path: tigeropen.common.consts.filter_fields)
| Type | Description |
|---|---|
| StockField | Simple indicator filter conditions, including price (OHLC, latest price, etc.), volume, share capital, market value, price change, P/E ratio, turnover rate, and other factors. Filter field meaning explanation: Filter Field Description |
| AccumulateField | Cumulative indicator filter conditions, including cumulative price change, asset growth rate, net profit growth rate, earnings per share, net profit, operating profit, operating income, ROA (return on equity), operating cash flow, debt-to-asset ratio, etc. Cumulative indicator periods can be: last 5 minutes, last 5 days, 10 days, 20 days, last half year, one year, two years, five years, Q1 report, Q3 report, interim report, etc. Filter field meaning explanation: Filter Field Description |
| FinancialField | Financial indicator filter conditions, including gross profit, net profit margin, total debt/shareholders' equity, total debt/total assets, current ratio, return on assets, net profit, operating cash flow, total assets, Hong Kong Stock Connect net purchases, annualized return, etc. Financial indicators currently only support LTM (Last Twelve Months annual report indicators) type financial report queries. Filter field meaning explanation: Filter Field Description |
| MultiTagField | Multi-label association filter conditions, based on industry, concept, historical stock price high (current day stock price compared to historical prices), 52-week stock price high (current day stock price compared to last 52 weeks), whether OTC, whether options are supported, stock type (stock, ETF), whether broken IPO, etc. Filter field meaning explanation: Filter Field Description |
The currency of price fields in filter parameters is consistent with the currency type of the market where the underlying asset is located, such as US stocks: USD, Hong Kong stocks: HKD, Singapore stocks: SGD, etc.
Returns
tigeropen.quote.domain.filter.ScannerResult
Structure 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 Filter stocks with dividend yield greater than 5% and revenue 3-year compound annual growth rate 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 | US for US stocks, SG for Singapore stocks, HK for Hong Kong stocks |
| tag_fields | list[tigeropen.common.consts.filter_fields.MultiTagField] | Yes | Supported field enum values: MultiTagField.Industry, MultiTagField.Concept |
Returns
list. Each item as follows:
| Field | Type | Description |
|---|---|---|
| market | str | Market code (US: US stocks, CN: A-shares, HK: Hong Kong stocks) |
| multi_tag_field | str | Multi-tag field |
| 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 1 day ago
