Open-source project
waditu/czsc avatar
waditu/czsc

waditu/czsc: Chan theory technical analysis with a Rust core

缠中说禅技术分析工具;缠论;股票;期货;Quant;量化交易

6,347 stars1,765 forksRustNOASSERTION

At a glance

What is it?
czsc implements Chan theory (缠论) fractals, strokes and pivots in Rust and exposes them to Python through PyO3. It is built for quant researchers working on Chinese equities and futures, and it expects you to bring your own data.
Who is it for?
Adopt czsc if you already work in Python on Chinese equities or futures and want fractals, strokes and pivots computed in Rust rather than reimplemented by hand. Do not adopt it if you need a ready-made data feed and a strategy that trades without your own signal and position code, or if your team cannot ship a Rust toolchain for source builds.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

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

Editorial analysis

What czsc solves, and who it is actually for

Chan theory describes price action as a hierarchy: fractals (分型) mark local turning points, strokes (笔) connect them, and pivots (中枢) are the overlapping ranges those strokes produce. Doing this by hand in pandas is slow and easy to get subtly wrong, because every level depends on the level below it. czsc exists to compute that hierarchy for you and then let you attach signals and positions to it.

The audience is narrow on purpose. The README describes a 信号-事件-交易 pipeline (signal, event, trade), and the package ships connectors for 天勤, Tushare and CCXT, which points at Chinese futures, A-share data and crypto respectively. If you are doing discretionary chart reading, this library gives you nothing you cannot get from a charting platform. If you are writing research code that needs the same stroke and pivot definitions across thousands of symbols, the value is in the consistency.

The Rust core and the Python surface

Version 1.0 moved the Chan algorithms out of Python. The README states that fractals, strokes and pivots are now implemented in Rust and exposed through a PyO3 extension at czsc._native, and that the old Python implementation lives in the 0.9.X branch. That is a real migration, not a wrapper: the objects you construct (CZSC, FX, BI, ZS, RawBar, BarGenerator) come from the compiled module.

The workspace holds nine crates, including czsc-core, czsc-signals, czsc-trader and czsc-python, which is the PyO3 binding entry point. Above them sits a thin Python layer: czsc.traders as a facade over the Rust trading API, czsc.utils for plotting and statistics, czsc.connectors for data sources, and czsc.strategies for strategy classes. Signal functions are the largest surface, with the README claiming 220+ functions implemented in Rust under czsc._native.signals and organised into seven Python-side submodules.

One detail worth noting: the README says the Rust TA operators (ema, sma, boll and similar) are now internal only. If you were importing those directly, that path is closed.

Installing czsc and running a first Chan analysis

The README requires Python 3.10 or newer. The recommended route is a prebuilt wheel from PyPI, which avoids the Rust toolchain entirely:

bash
pip install czsc -U

For a development environment the README suggests uv instead:

bash
uv pip install czsc

If you need to build from source, you need Rust and maturin. The README points at rustup.rs for Rust, then:

bash
pip install maturin
git clone https://github.com/waditu/czsc.git
cd czsc
maturin develop --release

There is a build trap here that the README calls out explicitly. The pyo3 and pyo3-stub-gen 0.22 dependencies require Python 3.10+, and when the system default interpreter is older, cargo build and cargo test panic early inside crates/czsc-python/build.rs. The documented fix is to point PyO3 at a newer interpreter:

bash
export PYO3_PYTHON=$(which python3.12)

The README adds that the uv route (uv sync --extra dev) selects the project's declared Python automatically and does not need this variable.

With the package installed, the quickest real use is the mock data path, which needs no API key. The README generates synthetic 30-minute bars, converts them to RawBar objects and constructs a CZSC object:

python
import czsc
from czsc import CZSC, Freq, format_standard_kline
from czsc.mock import generate_symbol_kines

df = generate_symbol_kines('000001', '30分钟', '20240101', '20240601')
bars = format_standard_kline(df, freq=Freq.F30)
czsc_obj = CZSC(bars)
print(f"笔数量:{len(czsc_obj.bi_list)}")
print(f"中枢数量:{len(czsc_obj.zs_list)}")

If the install worked, that prints nonzero stroke and pivot counts. From there the README shows BarGenerator for multi-timeframe synthesis, generate_czsc_signals for signal sequences, and WeightBacktest for weight-based backtests.

Multi-timeframe work and the signal naming convention

Chan analysis is inherently multi-level, and czsc handles that with BarGenerator. You declare a base frequency and the frequencies you want derived from it, feed raw bars in, and read the synthesised bars back out by frequency key:

python
from czsc import BarGenerator, Freq

bg = BarGenerator(base_freq='1分钟', freqs=['5分钟', '30分钟', '日线'])
for bar in raw_bars:
    bg.update(bar)

bars_5m = bg.bars['5分钟']
bars_30m = bg.bars['30分钟']

The signal layer uses string identifiers that encode a version date, for example czsc._native.signals.bar.bar_end_V230331. Two helper functions, get_signals_freqs and get_signals_config, parse a signal list to work out which frequencies it needs and what configuration it requires. That design is convenient for config-driven research but has a cost: the signal names are strings, so a typo surfaces at runtime rather than at import, and the version suffix means a signal you depend on can be superseded by a newer dated variant without the old name disappearing.

Where czsc stops and you have to start

czsc gives you structure and plumbing, not a strategy. The README's own examples end at run_replay and run_research, which take signals_seq and pos_seq arguments. Those sequences are yours to write. There is no bundled position-sizing rule, no risk model and no execution layer in what the README documents.

The data situation is similar. czsc.connectors exists and covers 天勤, Tushare and CCXT, but the README does not document credentials, rate limits or which endpoints are wrapped. The related searches include "Tushare API key", which suggests that is a common first obstacle, and the README itself does not answer it. Expect to read the connector source.

Build complexity is the other boundary. The prebuilt wheel is fine, but anyone who needs a source build inherits a Rust workspace, a pinned polars version and a Python version floor. The Cargo.toml comments explain that polars is held at 0.52.0 because polars-arrow 0.53.x pins chrono in a way that conflicts with pyo3-stub-gen, and that the upgrade waits on upstream. That is a reasonable call, but it means your dependency graph is constrained by decisions made two layers down.

How czsc differs from the alternatives people search for

The related searches name several projects in the same space, and they are not interchangeable. MyTT is a compact collection of technical indicator formulas, typically a single file of functions you copy into your own code. It computes indicators; it does not model Chan structure. If you want a moving average or an MACD, MyTT is the lighter answer, and czsc is overkill.

QUANTAXIS is a full trading framework with its own data storage, backtesting engine and account model. The difference in approach is scope: QUANTAXIS asks you to adopt its stack, while czsc assumes you already have data and a backtest and want the Chan layer plus signal composition on top. If you have no infrastructure at all, czsc leaves you assembling more pieces.

Chanlun implementations exist in several languages, and the distinction that matters for czsc is the Rust core. The README is explicit that 1.0.X moved the algorithms to Rust and that the Python implementation is the 0.9.X branch. If you want to read and modify the fractal and stroke logic in Python, the older branch is where that code lives.

Maintenance, licensing and what an upgrade costs

The repository is not archived, and the last push was on 2026-09-18, four days before this writing. Release 1.0.1 was tagged on 2026-08-09, following three release candidates between May and June. That is a project in the middle of stabilising a major rewrite, and the CHANGELOG.md at the repository root is where the breaking changes between 0.9.X and 1.0.X will be recorded.

Upgrade cost from 0.9.X is not small. The README tells you to look at the 0.9.X branch if you need the old Python logic, which implies the internal structure changed rather than just the implementation language. Anything that reached into Python internals will need rework. The single version source is a nice touch: pyproject.toml uses dynamic = ["version"] and maturin injects the version from the workspace Cargo.toml, so the Python and Rust sides cannot drift apart.

The licence needs care. pyproject.toml declares license = "Apache-2.0" and a matching classifier, while the workspace Cargo.toml declares license = "MIT". The repository metadata reports the licence as NOASSERTION, which is consistent with that mismatch. The pyproject.toml comments also record that an earlier release candidate failed to upload its sdist because license-files was missing, which is why the field is declared now. If you redistribute czsc in a product, read LICENSE and the per-crate manifests yourself rather than trusting a single field.

Editorial conclusion

Adopt czsc if you already work in Python on Chinese equities or futures and want fractals, strokes and pivots computed in Rust rather than reimplemented by hand. Do not adopt it if you need a ready-made data feed and a strategy that trades without your own signal and position code, or if your team cannot ship a Rust toolchain for source builds. Before committing, check the Python version is 3.10 or newer, confirm whether a prebuilt wheel exists for your platform so you can avoid maturin entirely, and read the licence files in both pyproject.toml and the workspace Cargo.toml, because they do not state the same licence.

Frequently asked questions

What is waditu/czsc used for?

It is a technical analysis library for Chan theory (缠论), covering the automatic identification of fractals, strokes and pivots, plus a signal-event-trade pipeline for quant research. The README lists A-share and futures use cases and ships connectors for 天勤, Tushare and CCXT.

How do I install czsc?

The README recommends pip install czsc -U for a prebuilt wheel, or uv pip install czsc for a development environment. Building from source requires Rust and maturin, and Python must be 3.10 or newer.

Does czsc need a Rust toolchain?

Only if you build from source. The README documents maturin develop --release for that path and notes that pyo3 and pyo3-stub-gen 0.22 require Python 3.10+, with PYO3_PYTHON available to point the build at a newer interpreter. Installing the prebuilt wheel avoids the toolchain entirely.

Which Python versions does czsc support?

The README states Python must be 3.10 or higher, and pyproject.toml sets requires-python to >=3.10 with classifiers for 3.10 through 3.13.

Official sources

  1. Issues
  2. README
  3. Releases
  4. waditu/czsc 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/waditu-czsc.svg)](https://hysenlabs.com/projects/waditu-czsc)