jgt-pricedb
The persistence layer of the next-generation Price Service: bars live in a database with an incremental, anchor-based refresh — CSV files become an export, not the source of truth.
Lineage: implementation of the PDSP specifications reverse-engineered from
the Caishen .NET stack — caishen/rispecs/PDSP/ (specs 70–77) — translated
into the jgt ecosystem's shapes.
Structural Tension
- Current reality: price data as flat CSVs (
$JGTPY_DATA/pds/<INSTR>_<TF>.csv); every refresh rewrites whole files and downstream recomputes whole series. - Desired state: a database-backed store where refresh finds the anchor (the single forming bar per series) and writes only forward; downstream learns which bar changed and computes incrementally.
Decisions
Production ownership (2026-09-04)
The projection contract is in production: jgtpdb derive-cds
(jgtpricedb-util 0.2.0) materializes indicator-complete CDS from a PDS
export, and the jgt-data-server updater builds its rolling CDS through the same
materialize_cds seam. The Williams engine (jgtpy) is a dependency of that
job alone; no chart service imports it.
PDS (today: written by the updater's broker fetch, jgtfxcon)
-> jgtpdb derive-cds / materialize_cds -> indicator-complete CDS -> chart
The CDS layer is database-native (2026-09-09)
Phase 5's first table exists: cds_rows, keyed (series_id, ts_utc) against
bars, indicators in JSONB. jgtpdb derive-cds-db computes them from stored
prices through the same Williams engine the file projection uses, and
SqlPriceStore.read_cds joins the two in one indexed read. The data server's
services/price_store reads chart history from there when
JGT_PRICE_STORE_URL is set, which collapses the rolling/deep/CDS/PDS merge
the files required — one series holds every depth.
Two things the DB path had to learn that the file path got for free:
- The engine is fed the export quantum, not the raw arithmetic. A mid is
(bid+ask)/2and carries binary dust:1.1672699999999998where the quotes say1.16727. The CSV job never saw it because its input had already been rendered throughCsvFormat. Feeding the dust through made a Williams fractal fire on one bar of 941 on live EUR-USD H1. With the quantum applied, the two paths are identical across 62 indicator columns and 941 bars. - A non-finite indicator is null, not a number.
mfiis range over volume and divides by zero on a bar the broker published with none. The CSV spells thatinf; JSONB has no infinity, and arithmetic on one propagates it.
What is not yet true: the store is not the production PDS writer. The
updater's fetch still writes current/pds and the store ingests from it
(updater/src/store_worker.py); jgtpricedb export becomes the source at the
cutover. One writer at a time. TTF and MLF remain future layers on the same
seam.
- Periods are cut on the broker's trading session, not on UTC midnight
(0.1.1). The feed publishes H4, D1, W1 and M1 bars on a 17:00
America/New_York boundary — 21:00Z in summer, 22:00Z in winter — so a UTC grid
renamed 100% of them, silently.
m1..H1stay on UTC, where they measurably already were. The session is stated per market, resolved insidebar_key, and recorded on the series;tests/test_session_grid.pyis the measurement, run against the real holdings. Seerispecs/01-price-store.spec.md, The Session Grid. - Portable schema (SQLite for local-first dev, PostgreSQL for deployment);
the anchor invariant is enforced by a partial unique index
(
UNIQUE(series_id) WHERE is_forming), not by application discipline. - No standalone importer. Backfill is the refresh engine's bootstrap path
(PDSP spec 72, Algorithm C) fed by a source adapter.
CsvSourcereads the existingfull/CSVs through the exact same upsert path asBrokerSourcelive updates. The system can always rebuild itself from its own sources. - CSV compatibility export (PDSP spec 75 pattern, 0.1.2): consumers
(
jgtpy,jgtml,jgt-data-server) keep reading the same file paths while the database becomes authoritative underneath. The format is measured rather than assumed — quotes keep the double the feed published, the derived columns are quantized at display precision +1 and +2 (with builtinround, which is not the one pandas reaches for), and the line terminator belongs to the file being replaced. A holdings file read in and written back out is byte-for-byte itself: 89 of 89 live files, 13 instruments, all seven timeframes, 95 208 bars. Seerispecs/03-csv-export.spec.md. - Redis pub/sub (already in the jgt-data-server stack) carries bar-completed events in Phase 4 — the role Rebus/MSMQ played in Caishen.
pyproject.tomlwith a static version — deliberately avoiding thesetup.pycircular-import pattern that blocks other jgt packages from installing in containers.
Phases
| Phase | Creates | PDSP spec |
|---|---|---|
| 1 | Schema + store core + bootstrap-backfill through source adapters | 70, 71, 72 |
| 2 | Jobs (jgtpdb) replacing refresh_data.sh — shipped as jgtpricedb-util |
72, 74 |
| 3 | CSV export bridge — DB authoritative, downstream untouched (0.1.2) | 75 |
| 4 | Redis events → incremental IDS/CDS recompute | 73, 77 |
| 5 | Serving from DB; indicator tables (CDS layer 0.2.0); strategy layer (SpiderDb heir) | 76 |
Layout
rispecs/— jgt-native specifications (the buildable truth; start here)src/jgtpricedb/— the librarydocker-compose.yml— optional Postgres for deployment; SQLite needs nothing../jgt-pricedb-util/— the sibling package (jgtpricedb-util): the jobs an operator runs against a store — bootstrap, refresh, a bounded forming-bar loop, an OANDA fetch on this session grid, and the freshness and relabel probes. This repository is the store; that one is the steward.
Metadata
Release files for jgtpricedb 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| jgtpricedb-0.2.1.tar.gz | 133.1 kB | Without provenance | Details for jgtpricedb-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| jgtpricedb-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for jgtpricedb-0.2.1-py3-none-any.whl |
Total release size: 186.9 kB
Release files / jgtpricedb-0.2.1.tar.gz
| Download URL | jgtpricedb-0.2.1.tar.gz |
|---|---|
| Size | 133.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
37e654378b5c5b4ec12f3ea78a747e157329936882587c1916a4930fc75376e0
|
|
BLAKE2b-256 checksum How to use checksums |
07823b9f3bf556ba1dffeee0bec9c85208c05936d0d7512ff99abe8349355d61
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Release files / jgtpricedb-0.2.1-py3-none-any.whl
| Download URL | jgtpricedb-0.2.1-py3-none-any.whl |
|---|---|
| Size | 53.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
62ea0934d023dbf2fd133d12beb903ef52d25c18c477796af8caa16daaf9c3f2
|
|
BLAKE2b-256 checksum How to use checksums |
48d55eab4386b48305b217765cd7cfcbc98efce5c4fc827a7e2e2e873a95b36f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.4
|
Security for jgtpricedb 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.