free-stockdb: A Local A-Share Data Engine for Batch Backtesting
面向 A 股日K、分钟K与ETF分钟数据的本地量化引擎,集成增量同步、本地缓存、复权、批量查询、回测与指标计算。
At a glance
- What is it?
- free-stockdb packages A-share daily, minute and ETF data into a local C++ time-series service with Python, HTTP, Excel, HTML and MCP access. The README's central claim is that full-market backtesting fails on remote APIs not because of strategy code but because of data engineering, and the project positions itself as the layer that removes that work.
- Who is it for?
- Adopt free-stockdb if your work is full-market A-share research where the bottleneck is data preparation rather than execution, and you are willing to trust a sync pipeline whose upstream source you configure yourself in sync_url.txt. Do not adopt it if you need intraday live trading, exchange-licensed data with contractual guarantees, or a maintained public API with versioned deprecation policy.
- 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 last received commits 8 days ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem free-stockdb targets: data engineering, not strategy code
The README makes an argument rather than a feature list. It claims that a full-market backtest over 7000+ stocks on minute bars does not fail because the strategy is hard to write, but because assembling the data takes longer than writing the strategy. The project's own breakdown puts a remote-API workflow at 10 to 15 working days before a first full-market strategy runs, split across downloading, cleaning suspensions and delistings, computing adjustment factors, choosing a database, writing indicator formulas and wiring up multiple client interfaces. Those figures are the project's claims about its own comparison, not measured results, and the README does not describe the hardware or network conditions behind them. Treat them as a statement of intent about where the project aims its effort.
The audience is implied by that framing: individual quant researchers and small teams working on A-share daily and minute data who currently maintain their own pandas pipelines, their own adjustment logic and their own caching. It is not aimed at anyone who needs a hosted API with a support contract, and it is not aimed at live execution. The README describes a research and backtesting data layer, and nothing in the material covers order routing or broker connectivity.
How the local engine is structured: sync layer, storage, query layer
The architecture is a pipeline with a hard boundary in the middle. On one side, a sync tool reads a source address from sync_url.txt, pulls history once, then processes only changed data on subsequent runs, with Zstd compression on the wire and on disk, checksum verification against a manifest, and resume support for interrupted transfers. On the other side, everything reads from local storage: queries, indicator calculation, backtests and the five client interfaces never touch the remote source. The README's diagram shows the sync step feeding a single local engine, which then exposes Python SDK, HTTP API, Excel/WPS, HTML and MCP.
Storage is a custom C++ time-series service rather than a general database. The README states that historical data is stored Zstd-compressed and occupies less than a third of an equivalent CSV or MySQL layout, and that a second storage area under ./mydb accepts user-written data through a pipeline API. Data is kept unadjusted at rest, with adjustment factors stored alongside; forward-adjusted, backward-adjusted and raw views are computed at query time. That is a deliberate choice with a visible consequence: changing an adjustment convention does not require rewriting history, but every adjusted query pays the computation cost. The README does not state how large that cost is.
Sync sources are multi-point. The sync_url.txt format maps a source (a site or a path) to a data type and a destination directory, so minute data, daily data and tick data can come from different places and land in different paths, and rd.get() with no arguments reads across all mounted data.
The three query entry points and what each one is for
The README separates querying into three functions with distinct jobs. rd.get_data() takes code, start, end, frequency, fq, fields and an as_df flag, and is positioned for full-market, long-range, field-filtered reads across 7000+ stocks or ETFs, returning a list, dict or DataFrame. zb.get() takes a comma-separated indicator name list, codes, a time range, frequency, fq, per-indicator parameter lists via n, and a cross argument that returns either raw indicator values, golden-cross signals, or both. bk.get() handles the mapping between stocks and boards, taking a code, a board name or code, or a batch of stocks, with category selecting concept boards or Shenwan level 1, 2 or 3.
The README also documents an expression-style query layer on top of rd: get, keys, vals, len, delete, set, setr and setl, with support for ranges written as a>b, regular-expression matching, sorting, slicing with [:num], iteration and sub-node access. That layer is what the private-storage examples use, including a chained form like rd.get(table, key, key2).get("sub_key").set("sub_sub_key").val("new_value") for modifying a nested field.
Indicator coverage is stated as 39 indicators across trend, oscillator, channel, volume-price and composite groups, plus five index weighting methods (equal weight, free-float market cap, turnover, volume and total market cap). The README claims the Rust calculation core is three times faster than pandas and completes full-market indicator runs in seconds. That number is the project's own and is not accompanied by a benchmark method, dataset size or machine specification, so it should be treated as an unverified claim until you reproduce it on your own hardware.
Getting it running: release package first, CMake second
The documented path for Windows users is a release download rather than a build. The README's four steps are: run the data update tool, let data sync into ./data, start stockdb (described as 2.2 MB), then query through any of the five interfaces. Releases are listed for Windows, macOS, Alpine and manylinux, with the most recent release named 测试版本0.3.5. The README also notes a download address that appears truncated in the source text, so the Releases page is the reliable route.
Building from source targets the C++ components in cpp/ and requires CMake 3.14 or later, a C++17 compiler, libcurl and OpenSSL development packages. The two documented commands are:
cmake -S cpp -B cpp/build cmake --build cpp/build --config Release
Configuration lives in sync_url.txt, which the README describes as accepting multiple source entries, each with a type and a destination path. The HTTP interface is documented as listening on http://127.0.0.1:7899/ with a cmd=get query form. The README states that the service binds to 127.0.0.1 by default and does not expose itself publicly, that the synchronizer only contacts the address given in sync_url.txt or via --source, and that an empty configuration means no sync request is made. It also states that sync files are verified against SHA-256 and size in the manifest before being written, and recommends HTTPS for public sync nodes and checking the published SHA-256 of the release package. Those are documented behaviours, not independently verified ones.
Hardware guidance is modest: about 5 GB of disk for daily bars only, about 20 GB with full minute data, 2 GB of RAM minimum and 8 GB or more recommended, with Windows 7+ listed as the minimum OS.
Where the design creates friction
The most consequential limitation is the one the README states plainly and then works around: the project does not ship a data source. sync_url.txt is a pointer, and the quality, coverage and licensing of what flows through it are the user's problem. The README says so directly in the licensing section, noting that data copyright, usage authorization and redistribution terms are determined by each data source and its rights holders. A user who configures a source that later changes its terms, throttles, or disappears keeps the data already on disk but has no guaranteed path to updates. The README's answer is that snapshots remain queryable offline and the source can be swapped without changing the query layer, which is true of the architecture but does not restore data you never received.
A second friction point is the release history. The repository lists one recent release, version 0.3.5, and the README's own changelog lines reference dates in August and the release is dated 2026-07-19. The version string is prefixed with 测试版本 (test version). There is no documented compatibility policy, no deprecation schedule for the query protocol, and no stated minimum version for the Python SDK against a given server build. If you build a research pipeline on rd.get_data() and zb.get() today, you have no documented guarantee about when those signatures change.
A third is the platform gap in the README's own text. The opening lines describe macOS, Linux and manylinux builds as completed and stress-tested but pending release at the time of writing, while the hardware table lists only Windows 7+ and Windows 10+. The build-from-source route covers the gap if you have a C++17 toolchain and the curl and OpenSSL development packages, but the two-minute path is documented for Windows.
Finally, the tick-level data is described as available on demand, not as part of the default dataset, and the storage sizing table does not account for it. Anyone planning tick-level research should treat the disk and sync-time figures as unstated.
How it differs from a pandas-plus-remote-API stack
The realistic alternative for most readers is not another product but the stack they already have: a remote market-data API for A-shares, pandas for transformation, Parquet or a local database for storage, and hand-written indicator functions. The difference is not speed in the abstract. It is where the boundary sits.
In the remote-API stack, every research run is coupled to the API's rate limits, token state and availability, and the adjustment factors, suspension handling and code-change history are things you implement and maintain. In free-stockdb, that coupling is confined to the sync step, and the query, indicator and board-mapping layers read from disk. The consequence is that a backtest over the full market does not consume API quota, and an offline machine can still run it. The cost is that you now operate a local service on 127.0.0.1:7899 and manage a data directory whose contents you are responsible for verifying.
The second difference is the indicator layer. Writing MA, MACD and KDJ in pandas is not hard; making full-market rolling computation finish in reasonable time is the part that pushes people toward compiled extensions or chunked processing. free-stockdb moves that into a Rust core behind zb.get() with per-indicator parameters and an optional cross-detection mode. Whether the claimed three-times-pandas figure holds on your data is something you can check in an afternoon by running the same indicator set through both.
A third difference is the interface surface. A pandas stack typically ends at a DataFrame in a notebook. free-stockdb exposes the same local data through HTTP on port 7899, through Excel and WPS, through an HTML page, and through a self-implemented MCP endpoint that Claude, Cursor and Windsurf can connect to without installing an MCP SDK. For a solo researcher that breadth may be unused; for a small team where one person lives in Excel and another in a notebook, it removes a handoff.
Maintenance, licence and what to check before you commit
The repository is MIT licensed, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are retained. That covers the code. It does not cover the data. The README is explicit that data copyright, usage authorization and redistribution conditions belong to each data source and its rights holders, and that users must confirm the terms themselves. This is not legal advice; if you plan to redistribute derived datasets or use them commercially, the licence file in the repository does not settle that question and the data source's terms do.
Maintenance cost has two components. The first is the software: one release is listed, the version is marked as a test version, and there is no published compatibility policy. Upgrading means re-reading the README's changelog lines and re-running your own query code against the new build, because nothing in the material promises the protocol is stable. The second is the data: the sync tool handles incremental updates and resume, but the source behind sync_url.txt is yours to choose and yours to monitor. If that source degrades, the engine keeps working on what is already on disk and stops receiving new bars.
Before adopting, verify the source. Point sync_url.txt at a node you control or have evaluated, sync a subset, and check that the adjustment factors reproduce against at least a few corporate actions you already know the dates and ratios for. The README offers this check itself, noting that adjustment factors, prices, volumes and corporate-action dates can be sampled through the local interface. Then confirm the release package hash against the SHA-256 published for that version, as the README instructs. If those three checks pass on your data and your hardware, the architecture does what it claims: it decouples data preparation from strategy research. If the source you can access does not cover the history you need, no amount of local query speed compensates.
Editorial conclusion
Adopt free-stockdb if your work is full-market A-share research where the bottleneck is data preparation rather than execution, and you are willing to trust a sync pipeline whose upstream source you configure yourself in sync_url.txt. Do not adopt it if you need intraday live trading, exchange-licensed data with contractual guarantees, or a maintained public API with versioned deprecation policy. Before committing, verify three things: that the data source you point sync_url.txt at covers the minute and tick history you need, that the adjustment factors reproduce against a sample of corporate actions you already know, and that the release package you download matches the SHA-256 published alongside it.
Community notes