TickFlow gives Python a unified symbol format across A-shares, US and HK
Professional financial data API for China A-shares, US & HK stocks. Python SDK with real-time quotes, K-line data & financial reports.
At a glance
- What is it?
- TickFlow is the official Python client for the TickFlow market data API, covering China A-shares, ETFs, US and Hong Kong stocks, with a free tier for daily K-line data and instrument lookups. The design detail worth knowing is the unified symbol format, where every market is addressed the same way.
- Who is it for?
- TickFlow suits a Python team building a China-focused market data service that wants one client and one symbol format across A-shares, ETFs, US and Hong Kong equities, and that is comfortable with a hosted market data provider rather than a self-run feed.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 55 days ago.
- 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 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
One symbol format across five market suffixes
The design decision that makes the SDK pleasant to use is the symbol format. Every endpoint that queries by instrument takes a unified code of the form code.market-suffix, with a dot in the middle, and the code part is the official exchange code.
The suffixes are listed in a table. SH is the Shanghai Stock Exchange, covering Shanghai A-shares, ETFs and bonds. SZ is the Shenzhen Stock Exchange, covering Shenzhen A-shares, the ChiNext board and ETFs. BJ is the Beijing Stock Exchange. US is the United States market, and HK is Hong Kong.
The examples given cover the range. For stocks there is 600000.SH, 000001.SZ and 920662.BJ. For ETFs there is 510300.SH and 159915.SZ. For indices there is 000001.SH for the Shanghai Composite and 399006.SZ for the ChiNext index. The same rule then extends to non-China markets, where the code part is the ticker and the suffix carries the exchange, so AAPL.US and 00700.HK are the natural forms.
The practical payoff is that a function which takes a symbol does not need to know which market it is dealing with. If you are building a screening tool over a mixed universe, you can hold a list of codes from several markets and pass them to the same call:
quotes = tf.quotes.get(symbols=["600000.SH", "000001.SZ"], as_dataframe=True)
print(quotes)For A-shares, the documentation states the support is already there: real-time quotes, daily K, minute K, intraday time series, financial data and universe queries such as CN_Equity_A. US and HK are listed as supported too, with real-time quotes, full historical daily K including forward and backward adjustment, ex-dividend factors, and universes named US_Equity and HK_Equity.
A free tier that is honest about what it leaves out
The free service needs no registration and no API key, which makes it easy to evaluate before signing up for anything.
The free client is constructed with a class method:
from tickflow import TickFlow
tf = TickFlow.free()What you get is stated as a list with the exclusions spelled out just as clearly. The free service provides historical daily K-line data at the 1d, 1w, 1M, 1Q and 1Y periods, plus instrument information, exchange information and universe queries. It does not provide real-time quotes, and it does not provide minute-level K-lines at 1m, 5m, 15m, 30m or 60m. The daily data is historical and does not update intraday.
A free-tier session looks like this:
from tickflow import TickFlow
tf = TickFlow.free()
df = tf.klines.get("600000.SH", period="1d", count=100, as_dataframe=True)
print(df.tail())and the instrument lookup is the same client with a different namespace:
from tickflow import TickFlow
instruments = tf.instruments.batch(symbols=["600000.SH", "000001.SZ"])
print(instruments)The documentation is explicit about when to move up. If you need real-time quotes, intraday K-lines or higher-frequency access, you should use the full service.
That is a reasonable free tier for a market data API, and the important thing is that the boundary is documented rather than discovered. A user who discovers it by getting empty minute bars at 9:31am has learned something the documentation would have told them for free.
Authentication by key, by environment variable, or by doing nothing
The full service needs an API key, which you generate from the console at tickflow.org after logging in. The client accepts it in three ways, and the difference between them matters for how you deploy.
Passing it directly is the simplest form:
from tickflow import TickFlow
tf = TickFlow(api_key="your-api-key")Reading it from the environment is the one to use in production, and the SDK picks it up automatically when you construct the client with no arguments:
The variable is TICKFLOW_API_KEY, and the documentation gives the export for Linux and Mac:
export TICKFLOW_API_KEY="your-api-key"with separate Windows forms for PowerShell and CMD using $env:TICKFLOW_API_KEY and set TICKFLOW_API_KEY respectively.
Once configured, the first request is a quote lookup, and the documentation says that if you see stock prices printed, the SDK is configured correctly:
from tickflow import TickFlow
tf = TickFlow(api_key="your-api-key")
quotes = tf.quotes.get(symbols=["600000.SH", "000001.SZ"])
for q in quotes:
print(f"{q['symbol']}: {q['last_price']}")The full service adds real-time quotes, minute-level K-lines at 5m, 15m, 30m and 60m, intraday time series data, and higher call frequency. Note that 1m appears in the free tier's exclusion list but not in the full service's feature list, so the exact availability of one-minute bars for a paid key is something to confirm against the API reference rather than assume.
K-lines have a 10000 bar ceiling, and batching is the answer
There is a hard limit on how much history one call can return: a single call for a single symbol returns at most 10000 K-lines. Anything longer has to be requested in pieces.
For a single symbol, tf.klines.get takes the symbol and the parameters:
from tickflow import TickFlow
tf = TickFlow(api_key="your-api-key")
df = tf.klines.get("600000.SH", period="1d", count=10000, as_dataframe=True)
print(df.tail(5))and adding as_dataframe=True returns a pandas DataFrame instead of the raw structure, which the documentation notes requires pandas to be installed.
For many symbols, tf.klines.batch is the intended path, and the documentation says it suits large numbers of instruments:
from tickflow import TickFlow
tf = TickFlow(api_key="your-api-key")
symbols = ["600000.SH", "000001.SZ", "600519.SH"]
dfs = tf.klines.batch(symbols, period="1d", count=10000, as_dataframe=True, show_progress=True)
print(list(dfs.keys()))The batch method returns a mapping keyed by symbol, so you address each result by its code.
Intraday data is a separate namespace, tf.klines.intraday, which returns the current day's minute bars for one symbol or for many. It accepts a period argument for the bar size and a count argument if you only want the most recent bars. The batch variant, tf.klines.intraday_batch, takes the same show_progress argument.
The show_progress flag and the progress extra are the same idea from different ends: the client can render a progress bar during a long batch, and you install it with the progress extra. It is a small thing that tells you the SDK was written for the case where a request takes a while.
Universes let you ask for a whole market instead of a list
The quotes endpoint has a second form that goes the other way from a symbol list. Instead of naming instruments, you name a universe, and the client returns everything in it.
quotes_a = tf.quotes.get(universes=["CN_Equity_A"], as_dataframe=True)
print(quotes_a)and for ETFs:
quotes_etf = tf.quotes.get(universes=["CN_ETF"], as_dataframe=True)
print(quotes_etf)The documented universes include CN_Equity_A for A-shares, CN_ETF for the Shanghai and Shenzhen ETF universe, US_Equity and HK_Equity for the other two markets.
This is the feature that determines whether the paid tier is affordable for you. A screen that watches the whole A-share market at once is one call, and it is the call you would otherwise have to synthesise from several thousand symbol lookups. The free tier does list universe queries as available, so you can at least map the universe before paying for live data on it.
The caveat is the one you would expect. A full market snapshot is a large response, and the paid tier's higher call frequency is what makes such calls practical. Anyone planning to poll universes at high frequency should read the best practices page in the documentation, which the readme links as the place for production guidance.
An async client, and an installation with deliberate extras
For high concurrency, the SDK ships an async client, AsyncTickFlow, and the free variant works the same way with the same no-key construction:
import asyncio
from tickflow import AsyncTickFlow
async def main():
async with AsyncTickFlow.free() as tf:
df = await tf.klines.get("600000.SH", period="1d", as_dataframe=True)
print(df.tail())
asyncio.run(main())The paid form takes the key in the constructor and supports concurrent gathers:
import asyncio
from tickflow import AsyncTickFlow
async def main():
async with AsyncTickFlow(api_key="your-api-key") as tf:
df = await tf.klines.get("600000.SH", as_dataframe=True)
print(df.tail())The client is an async context manager, so it closes its connection pool when the block exits.
Installation is where the packaging choices show. The full install is:
pip install "tickflow[all]" --upgradeand the base install, if you do not need DataFrame support or the progress bar, is:
pip install tickflowThe extras in pyproject.toml are separate. There is a pandas extra at 1.5.0 or newer, a progress extra for tqdm at 4.60.0 or newer, and a realtime extra for websockets at 13.0 or newer for real-time WebSocket streaming, plus an all extra that bundles all three. The core dependencies are deliberately thin: httpx at 0.25.0 or newer and typing-extensions at 4.0.0 or newer, with httpx giving you both sync and async clients from one dependency.
The package supports Python 3.9 and newer, with the documentation recommending 3.10 or higher, and it is typed, with a Typing :: Typed classifier in the metadata. The dev tooling is datamodel-code-generator for the HTTP layer, pytest with pytest-asyncio, ruff and mypy.
The readme notes that for large amounts of K-line data you should use tf.klines.batch rather than concurrent single calls, which is a hint about where the rate limits bite.
Editorial conclusion
TickFlow suits a Python team building a China-focused market data service that wants one client and one symbol format across A-shares, ETFs, US and Hong Kong equities, and that is comfortable with a hosted market data provider rather than a self-run feed. It is the wrong choice if you need intraday or real-time data without registering, since the free tier explicitly excludes both, and the wrong choice if you need a private or broker-grade feed with exchange direct connectivity, which this API is not. Before building on it, run the free tier against your actual symbol list to confirm coverage and history depth, then compare the per-symbol cost of the paid tier against the call volume your application will generate, because the batching and universe endpoints exist precisely to control that volume.
Frequently asked questions
Can I use the TickFlow Python SDK without registering for an API key?
Yes. TickFlow.free() gives you a client with no key. The free service covers historical daily K-lines at 1d, 1w, 1M, 1Q and 1Y plus instrument, exchange and universe queries, but not real-time quotes and not minute-level bars, and the daily data does not update intraday.
How do I write a symbol for a Chinese stock, a US stock or a Hong Kong stock?
Every symbol is the exchange code followed by a dot and a market suffix. SH is Shanghai, SZ is Shenzhen, BJ is Beijing, US is the United States and HK is Hong Kong, so examples are 600000.SH, 000001.SZ, 920662.BJ, AAPL.US and 00700.HK. The same call accepts a list mixing markets.
How many K-lines can I request in one call and how do I fetch many symbols?
A single call for a single symbol returns at most 10000 K-lines. For many symbols, tf.klines.batch takes a list and returns a mapping keyed by symbol, and as_dataframe=True returns pandas DataFrames, with show_progress=True available for the progress bar.
Official sources
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.
[](https://hysenlabs.com/projects/tickflow-org-tickflow)Was this useful?