Skip to main content

data-store

Canonical market data archive library. The only interface through which the filesystem may be modified.

PyPI package: tt-data-store · GitHub: Tiny-Trader/data-store

Parquet is the source of truth. metadata.db (SQLite) catalogues instruments, files, ingestions, and validation — it is not a substitute for the archive.

Responsibilities

  • Push new data into the FS and maintain metadata
    • Normalize
    • Validate
    • Store
  • Get a slice of data from the FS

Callers own acquisition formats (e.g. CSV). Ingress is candles.write.

Mental model

Your script / collector
        ↓
  store.candles.write(...)
        ↓
normalize → validate → merge → atomic Parquet write → update metadata.db

Acquisition (CSV download, API, manual script) is the caller's job. The store only accepts normalized candle data via candles.write.

On disk, an archive looks like:

data/
├── market/          # Parquet files (human-readable layout)
├── reference/       # calendars, etc.
└── metadata.db      # catalogue

Canonical layout and semantics live in docs/.

Install

pip install tt-data-store
# or from source:
uv pip install -e .
from tt_data_store import MarketStore

Opening an archive

from tt_data_store import MarketStore

store = MarketStore("/path/to/data")

Optional S3 config (or env vars MARKETSTORE_S3_BUCKET, MARKETSTORE_S3_PREFIX, MARKETSTORE_S3_REGION):

from tt_data_store import MarketStore, RemoteConfig

store = MarketStore(
    "./data",
    remote=RemoteConfig(bucket="my-bucket", prefix="archive", region="ap-south-1"),
)

Usage

Register instruments

# NIFTY index
spot = store.instruments.create(
    exchange="NSE",
    instrument_type="INDEX",
    symbol="NIFTY",
)
# → instrument_key: "NSE:INDEX:NIFTY"

# NIFTY option
opt = store.instruments.create(
    exchange="NSE",
    instrument_type="OPTION",
    symbol="NIFTY",
    underlying_id=spot.id,
    expiry_date="2026-08-27",
    strike=25000,
    option_type="CE",
)
# → "NSE:OPTION:NIFTY:2026-08-27:25000:CE"

Look up later by key:

inst = store.instruments.get("NSE:INDEX:NIFTY")
all_nifty = store.instruments.list(symbol="NIFTY")

Write candles (main ingress)

Pass a list of dicts or a PyArrow table. Each candle has:

timestamp, open, high, low, close, volume (optional), open_interest (optional)

from datetime import datetime
from zoneinfo import ZoneInfo

IST = ZoneInfo("Asia/Kolkata")

rows = [
    {
        "timestamp": datetime(2026, 8, 11, 9, 15, tzinfo=IST),
        "open": 100.0,
        "high": 101.0,
        "low": 99.0,
        "close": 100.5,
        "volume": 10,
        "open_interest": 100,
    },
]

result = store.candles.write(spot, rows, source="upstox")

write handles normalization, dedup, merge with existing data, gap detection, atomic file replacement, and ingestion provenance. It returns a WriteResult with row counts, gaps, quality status (VALID / PARTIAL / etc.), and the file path.

Files land in deterministic locations — e.g. spot → market/nifty/spot/2026.parquet, options → market/nifty/options/2026-08-27/25000_CE.parquet.

Read candles

table = store.candles.read(
    spot,
    start="2026-08-01",
    end="2026-08-31",
)

Returns a PyArrow table, filtered and sorted by timestamp. The store resolves which Parquet files to read.

Inspect files and quality

file = store.files.get("market/nifty/spot/2026.parquet")

result = store.validate(spot)          # or store.validate(file.path)

report = store.inspect()

Sync with S3

Local writes go to disk first; S3 is separate:

store.remote.push(files=["market/nifty/spot/2026.parquet", "metadata.db"])
store.remote.pull(files=["market/nifty/options/2026-08-27/25000_CE.parquet"])
store.remote.sync(files=[...])

End-to-end producer flow

store = MarketStore("./data")

# 1. Ensure instrument exists
inst = store.instruments.get("NSE:INDEX:NIFTY")
if inst is None:
    inst = store.instruments.create(
        exchange="NSE", instrument_type="INDEX", symbol="NIFTY"
    )

# 2. Fetch from Upstox/NSE/CSV — convert to candle dicts yourself
candles = parse_my_csv("NIFTY.csv")

# 3. Single write call — store does the rest
result = store.candles.write(
    inst,
    candles,
    source="upstox",
    source_instrument_id="NSE_INDEX|Nifty 50",
    requested_start="2026-08-01",
    requested_end="2026-08-31",
)

# 4. Optionally push to S3
store.remote.push()

What not to do

  • Don't write Parquet files directly
  • Don't run SQL against metadata.db in normal workflows
  • Don't parse CSV inside tt_data_store — convert to candles first
  • Don't use paths as the primary interface (use instrument keys and date ranges)

Public API

store.instruments.get(...) / .list(...) / .create(...)
store.candles.read(...) / .write(...)
store.files.get(...) / .list(...)
store.validate(...)
store.inspect()
store.remote.pull(...) / .push(...) / .sync(...)

Repository layout

data-store/
├── docs/
├── pyproject.toml
├── src/            # tt_data_store package modules
└── tests/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tt_data_store-0.1.0.tar.gz (30.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tt_data_store-0.1.0-py3-none-any.whl (30.9 kB view details)

Uploaded Python 3

File details

Details for the file tt_data_store-0.1.0.tar.gz.

File metadata

  • Download URL: tt_data_store-0.1.0.tar.gz
  • Upload date:
  • Size: 30.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for tt_data_store-0.1.0.tar.gz
Algorithm Hash digest
SHA256 200ac90402e89137f36975fb57ab4e560039d6b2e57d9f76936e288e4ffbb71b
MD5 ac93f2228725a001185f429838b59b91
BLAKE2b-256 b54f841c7a75d0130bafea93c5143b1fef9cee6c5e9fe72515bc8e0f63f029a1

See more details on using hashes here.

Provenance

The following attestation bundles were made for tt_data_store-0.1.0.tar.gz:

Publisher: publish.yml on Tiny-Trader/data-store

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tt_data_store-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: tt_data_store-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 30.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for tt_data_store-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f834eae5db8683523bb66857ff39fc179d8635cf9f450bd3d18df6a0bb8ff3b7
MD5 9105d85802eff9f027239b0730611b02
BLAKE2b-256 d0b95ee38a28cea17f88be5cd63cec3c0de6302309b44e854b8164b856034044

See more details on using hashes here.

Provenance

The following attestation bundles were made for tt_data_store-0.1.0-py3-none-any.whl:

Publisher: publish.yml on Tiny-Trader/data-store

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

2.0.0

2 files

1.1.0

2 files

1.0.1

2 files

1.0.0

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page