Library / SDK
shner-elmo/TradingView-Screener avatar
shner-elmo/TradingView-Screener

tradingview-screener speaks TradingView's own API, and real time data costs you your browser cookies

A package that lets you create TradingView screeners in Python

1,330 stars182 forksPythonMIT

At a glance

What is it?
A Python package that builds TradingView screeners with a SQL-like query builder, returning a pandas DataFrame across stocks, crypto, forex, options and more, with 3000 or more fields and per field timeframes. Free data is delayed, and the package tells you how to check which mode each exchange is in.
Who is it for?
Adopt tradingview-screener if you want market screening and indicator data from TradingView in a Python script without building a scraper, and you are content with the default 50 row limit and delayed data. Do not adopt it for a high frequency polling loop, because the README asks you to be mindful of server load and potential bans.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The API is the interface, not a scraped page

tradingview-screener is a Python package that allows you to create custom stock screeners using TradingView's official API, and it retrieves data directly from TradingView without the need for web scraping or HTML parsing.

That distinction is the whole value proposition. A scraper breaks when the markup changes, and a scraper of TradingView in particular has to deal with a site that is heavily client rendered. Calling the same API the web client calls is stable in a way that scraping is not, and the returned data is structured rather than parsed.

The key features are compact. Stocks from around 70 countries, plus options, crypto, forex, CFDs, futures, bonds and more. Over 3000 data fields covering OHLC data, technical indicators, fundamental metrics such as P/E and EPS, and even internal TradingView-only fields. Timeframes from 1m through 1mo, which can be mixed freely per field with no subscription required. And filtering with SQL-like syntax and full support for AND and OR logic.

The installation is a single pip command.

bash
pip install tradingview-screener

The package name on PyPI is `tradingview-screener` while the import is `tradingview_screener`, and the current version in the metadata is 3.2.2. It is MIT licensed, requires Python 3.9 or newer, and is classified as Development Status 4, Beta, with typing marked as Typed.

The dependency list is short and tells you the shape of the result. `requests` for the HTTP calls and `pandas` for the data frames, with nothing else, so the package is thin and you get a DataFrame back rather than a custom object model.

The query builder returns a DataFrame with a shape worth understanding

The quickstart is a fluent chain that ends in a DataFrame.

python
from tradingview_screener import Query

x = (Query()
 .select('name', 'close', 'volume', 'market_cap_basic')
 .get_scanner_data())
print(x)

The output is a tuple of a count and the data frame, and the README shows the shape with 50 rows and 5 columns, listing tickers with their exchange prefix, the name, the close, the volume and the market cap. The count is the total number of matching rows, so the 50 is the default limit and not the size of the result set.

That limit is the detail to notice. By default the result is limited to 50 rows, and you can adjust it, but the README asks you to be mindful of server load and potential bans. That is the service's own position on the question, and it is the constraint that should shape your design. A screening tool that returns 50 rows by default is a tool for narrowing a universe, not for extracting one.

The advanced query shows the parts you will actually use.

python
from tradingview_screener import Query, col

(Query()
 .select('name', 'close', 'close|1', 'close|5', 'volume', 'relative_volume_10d_calc')
 .where(
     col('market_cap_basic').between(1_000_000, 50_000_000),
     col('relative_volume_10d_calc') > 1.2,
     col('MACD.macd|1') >= col('MACD.signal|1')
 )
 .order_by('volume', ascending=False)
 .offset(5)
 .limit(25)
 .get_scanner_data())

The `col` helper builds a column reference, and the operators are the Python ones, so `between`, comparison and boolean logic read naturally. The `|` suffix on a field name selects a timeframe, so `close|1` is the one minute close and `close|5` the five minute close, and `MACD.macd|1` is the one minute MACD. The advanced query compares two indicator values on the same timeframe, which is the kind of expression that a screener interface usually cannot express and that this one can, because the field name carries the timeframe.

Timeframes live in the field name, which is the neat trick

The README explains that some fields, usually prices and indicators, have multiple timeframes that you can choose from, and gives the mapping.

| Timeframe | Column | |---|---| | 1 Minute | `close\|1` | | 5 Minutes | `close\|5` | | 15 Minutes | `close\|15` | | 30 Minutes | `close\|30` | | 1 Hour | `close\|60` | | 2 Hours | `close\|120` | | 4 Hours | `close\|240` | | 1 Day | `close` | | 1 Week | `close\|1W` | | 1 Month | `close\|1M` |

Three things fall out of that table. The daily value has no suffix, which means the bare field name is the default timeframe and the suffix is the exception. The suffixes are not durations in minutes, since an hour is 60 and two hours is 120, so the encoding is a number of minutes with the letters W and M for the calendar periods. And the same suffix applies to indicators, which is what makes the MACD comparison in the advanced query work.

The mixing of timeframes is what the key features list calls out, and it is genuinely useful. A screener that can ask for the daily close and the one minute volume in the same query, without a subscription, is doing something a simple price fetch cannot.

The asset classes are reached through separate functions, and each returns a `Query` object, so you can chain the usual methods on top of them.

python
from tradingview_screener import stocks, crypto, options

stocks('italy').limit(5).get_scanner_data()
crypto().limit(5).get_scanner_data()
options('NASDAQ:AAPL').limit(5).get_scanner_data()

The full list of available screeners is `stocks`, `crypto`, `crypto_dex`, `coin`, `forex`, `futures`, `bond`, `cfd` and `options`. The `crypto_dex` and `coin` entries reflect that crypto comes in two flavours on TradingView, central exchange pairs and individual coins, and the distinction matters because the available fields differ.

The options example is the most involved, because options are queried by underlying symbol and then filtered on their own attributes.

python
(options('NASDAQ:AAPL')
 .select('name', 'close', 'ask', 'bid', 'expiration', 'volume')
 .where(col('expiration') == 20260427)
 .order_by('strike')
 .limit(10)
 .get_scanner_data())

The documentation also has a note for readers of the whole project: throughout the documentation, field and column are used interchangeably, and so are Scanner and Screener. That is a small thing, but in a project with this many identifiers it saves a search.

Real time data needs your cookies, and the package shows you the delay

This is the part of the README that is most practically useful, and it starts with a plain statement: to access real-time data you need to pass your session cookies, as even free real-time data requires authentication.

The package does not hide how to get them. The `rookiepy` library loads the cookies from your local browser, so if you are logged in on Chrome, or whatever browser you use, it will use the same session.

python
import rookiepy
cookies = rookiepy.to_cookiejar(rookiepy.chrome(['.tradingview.com']))

Then the cookies are passed into the query.

python
Query().get_scanner_data(cookies=cookies)

The `rookiepy.chrome` call is replaced with your browser, and the domain filter is the TradingView domain.

But the more interesting part is what the package lets you check. There is a query to get an overview of the `update_mode` you get for each exchange.

python
_, df = Query().select('exchange', 'update_mode').limit(1_000_000).get_scanner_data()
df = df.groupby('exchange')['update_mode'].value_counts()
print(df)

Without cookies the output shows AMEX, NASDAQ, NYSE and OTC all reporting `delayed_streaming_900`, which is a fifteen minute delay. With cookies, the same query shows AMEX, NASDAQ and NYSE reporting `streaming` and OTC still on the delayed mode, because the account's subscription does not include live data for OTC tickers.

That is a genuinely useful diagnostic, and it is the kind of thing most wrappers would leave you to discover by comparing prices. It also demonstrates the connection between the delay and the account, since the same query with and without cookies produces different modes, and the difference between exchanges within one session is a subscription boundary rather than a technical one.

The alternative to rookiepy is documented too, in a collapsed section on extracting cookies manually: go to TradingView, open the developer tools, navigate to the Application tab, then Storage, then Cookies, then the TradingView origin, and copy the value of `sessionid` to pass in your query.

That is worth reading as a design note. The package does not try to be clever about session handling. It hands you a cookie jar and lets you decide how to obtain it, which keeps it out of the business of managing credentials.

A small package with a documentation site and typed output

The repository is small and the tooling is modern. The root has a `src/` directory with the package, `tests/`, `templates/`, a `pyproject.toml` and a `uv.lock`, plus a `docs/` directory that produces the documentation site.

The build backend is hatchling, with the wheel packaging `src/tradingview_screener`, and the project requires Python 3.9 or newer with classifiers through 3.14. The development group is ipython, ruff, pdoc, pytest, pyright and pandas-stubs, and pdoc is what generates the API documentation. Ruff is configured with a target version of py39, a line length of 100, single quotes for the formatter and double quotes for docstrings, and a maximum doc length of 88.

That combination is worth noting. The package is typed, the `Typing :: Typed` classifier says so, and pandas-stubs and pyright in the dev group mean the type checking is real rather than aspirational. For a package whose main output is a DataFrame, that matters, because the column names it produces are dynamic and the only way to know what a query returns is to read the fields documentation.

The documentation site at shner-elmo.github.io/TradingView-Screener has separate pages for the fields, the markets and the screeners, with a versioned API reference. The fields page is the one to bookmark, because with 3000 or more fields across assets, timeframes and TradingView internal values, the field catalogue is the actual interface.

The recent releases are v3.2.1 from 2026-06-20, v3.2.0 from 2026-05-07 and v3.1.0 from 2026-02-26, and the last push to the repository was on 2026-10-15 with the repository not archived. The licence is MIT.

Editorial conclusion

Adopt tradingview-screener if you want market screening and indicator data from TradingView in a Python script without building a scraper, and you are content with the default 50 row limit and delayed data. Do not adopt it for a high frequency polling loop, because the README asks you to be mindful of server load and potential bans. Verify first that the fields you need exist in the fields documentation for your asset class, that the update mode for your exchange is the one you expect, and that the row limit and the frequency of your calls are acceptable to the service.

Frequently asked questions

What does tradingview-screener do and how do I install it?

It is a Python package that creates custom stock screeners using TradingView's official API, retrieving data directly without web scraping or HTML parsing. Install it with pip install tradingview-screener, and the import is tradingview_screener.

How do I get real time data instead of delayed data?

You pass your session cookies to the query, because even free real-time data requires authentication. The package uses rookiepy to load cookies from your local browser, and then you pass the cookie jar with get_scanner_data(cookies=cookies).

How do I select a different timeframe for a field?

You append a suffix to the field name, so close|1 is the one minute close, close|60 the hourly, close|1W the weekly and close|1M the monthly, while the bare close is the daily. The same suffix applies to indicators, which is how a query can compare a one minute MACD with its signal.

Which asset classes can the screener query?

The available screeners are stocks, crypto, crypto_dex, coin, forex, futures, bond, cfd and options. Each returns a Query object, so you can chain select, where, order_by, limit and the rest on top of it.

Why does my query only return 50 rows?

The result is limited to 50 rows by default and you can adjust the limit, but the README asks you to be mindful of server load and potential bans. Use the update_mode query to check the delay and streaming status of each exchange before you poll aggressively.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. shner-elmo/TradingView-Screener on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/shner-elmo-tradingview-screener.svg)](https://hysenlabs.com/projects/shner-elmo-tradingview-screener)

Was this useful?