Sakata
Pre-alpha research software. No API stability, no warranty, not for trading. Every interface here can change without notice until 1.0.0.
Sakata is a schema for financial time-series corpora and a way to build one reproducibly. A corpus is defined by a committed text file, not by whatever ended up on disk: delete the data, rebuild from the lock, and every file hashes the same.
Version 0.2.0 adds the data layer — two sources, a content-addressed cache, and the manifest that pins a corpus. There is still no model.
What this is not
- Not a trading system. There is no order routing, no broker integration, and no live market data.
- Not a backtester.
- Not a model. The tokenizer, the architecture, and the forecasting API arrive in v0.4.0 through v0.7.0.
Install
Development only — the repository is private and nothing is published.
uv sync --all-extras
CN A-shares need the optional cn extra; the core install stays numpy and
pyarrow.
Building a corpus
Three commands, and the lock is the artefact worth committing.
sakata data resolve examples/crypto-1h-dev.yaml -o corpus.lock.json
sakata data pull corpus.lock.json --dry-run # file count and byte total first
sakata data pull corpus.lock.json
sakata data verify corpus.lock.json
sakata data stats corpus.lock.json # read the anomalies
# corpus.yaml
name: crypto-1h-dev
sources:
- source_id: binance-spot-dumps
frequencies: [1h]
start: 2019-01
end: 2024-12
universe:
include_delisted: true
filters:
quote_assets: USDT
min_quote_volume_24h: 1_000_000
Commit the lock. Never the data.
Two sources ship: Binance spot archives and Baostock CN A-shares. Both record
their terms in a provenance registry, and neither can be loaded without one —
sakata data sources prints the table.
See docs/corpus.md for what each command does, and
docs/data-sources.md for what each source does that
will surprise you.
Using the schema
from datetime import datetime, timezone
from sakata import BarFrame, Frequency
frame = BarFrame.from_arrays(
timestamp=[datetime(2024, 1, 1, h, tzinfo=timezone.utc) for h in range(3)],
venue="BINANCE",
symbol="BTCUSDT",
frequency=Frequency.H1,
open=[100.0, 101.0, 102.0],
high=[103.0, 104.0, 105.0],
low=[99.0, 100.0, 101.0],
close=[101.0, 102.0, 103.0],
)
frame.to_parquet("btcusdt_h1.parquet")
print(frame.validate()) # ValidationReport(ok, 3 rows)
print(frame.close.mean()) # zero-copy numpy view
The conventions worth knowing
A bar's timestamp is its open time, in UTC. Not the close. Choosing close would mean converting on ingestion for every source, and a conversion applied inconsistently is how a lookahead bug gets into a backtest. Naive datetimes are rejected rather than assumed to be UTC.
An instrument is venue plus symbol, as two fields. AAPL trades on
several venues, and BTCUSDT differs between Binance and Bybit in both price
and volume. The venue is never encoded into the symbol string.
Delisted instruments are included. Binance retains delisted pairs in
exchangeInfo, so a survivorship-free universe costs nothing here — 243 of 733
USDT pairs at the time of writing. The liquidity floor deliberately skips them,
because a delisted pair reports no current volume and a floor applied to it
would exclude every one and quietly undo the correction.
Prices are stored unadjusted. Corporate-action factors are captured beside the bars and never applied. Adjusting at ingest is irreversible, so a policy change would otherwise mean downloading the corpus again.
All four are recorded with their reasoning in
docs/decisions.md, along with the six other decisions
that are expensive to reverse.
Development
See CONTRIBUTING.md. In short: uv sync --all-extras,
uv run pre-commit install, then uv run pytest.
Licence
MIT. See LICENSE and NOTICE — this project derives
from Kronos.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sakata-0.3.0.tar.gz.
File metadata
- Download URL: sakata-0.3.0.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d663cff30b046e58117a1971178922941f8d3640e22356a5a8330e343a94360
|
|
| MD5 |
74544080304ed511a92b6e98a564e28f
|
|
| BLAKE2b-256 |
bb41ce44e58039a55558fb8cdafaa58de77ef127144514b3df886b26ca0ec818
|
File details
Details for the file sakata-0.3.0-py3-none-any.whl.
File metadata
- Download URL: sakata-0.3.0-py3-none-any.whl
- Upload date:
- Size: 101.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7be39e4bddedd4a87494ad1c391c87957a2af45f13d1931fe84c4bd7ca8e83f
|
|
| MD5 |
7c3e2de4146337ef69184813ff099ff4
|
|
| BLAKE2b-256 |
1cdc28815e41d04c96ba076652e6c21f84706c4931c585755544fb4d1738aeb3
|