Apache Parquet Historical Time-Series Storage
π¦ Apache Parquet Historical Time-Series Storage
Section titled βπ¦ Apache Parquet Historical Time-Series StorageβStoring millions of historical price ticks and daily exchange rates directly inside a transactional SQLite database causes database bloat, degrades backup speeds, and degrades OLTP write throughput.
Kryptofolio delegates historical time-series storage to Apache Parquet files organized in a Hive-partitioned directory hierarchy.
ποΈ Hive Partitioning Directory Structure
Section titled βποΈ Hive Partitioning Directory StructureβHistorical pricing data downloaded from market providers is persisted to disk under the following layout:
data/βββ historical/ βββ prices/ βββ year=2024/ β βββ month=01/ β β βββ btc_eur.parquet β β βββ eth_eur.parquet β βββ month=12/ βββ year=2025/ βββ month=06/ βββ sol_eur.parquetWhy Hive Partitioning?
Section titled βWhy Hive Partitioning?β- Partition Pruning: When an analytical query requests portfolio valuations for 2025, DuckDB automatically skips reading folders for 2023 and 2024 without scanning the disk.
- Extreme Compression: Columnar storage with Snappy/ZSTD compression reduces financial time-series disk footprints by over 90% compared to traditional SQL tables or raw CSV/JSON files.
π Federated Queries in DuckDB
Section titled βπ Federated Queries in DuckDBβDuckDB natively reads Parquet files directly from disk without requiring any import or loading step:
-- Direct federated scan with predicate pushdown:SELECT price_timestamp, price_eur, volume_24hFROM read_parquet('data/historical/prices/year=2025/**/*.parquet')WHERE asset_symbol = 'BTC'ORDER BY price_timestamp ASC;π Zero-Copy ASOF Joins with SQLite
Section titled βπ Zero-Copy ASOF Joins with SQLiteβDuring daily portfolio valuation, DuckDB federates data across both storage engines simultaneously:
SELECT tx.timestamp, tx.amount_in, p.price_eur, (CAST(tx.amount_in AS DECIMAL(38,18)) * p.price_eur) AS cost_basis_eurFROM ledger.spot_transactions txASOF JOIN read_parquet('data/historical/prices/**/*.parquet') p ON tx.asset_id = p.asset_id AND tx.timestamp >= p.price_timestamp;ledger.spot_transactionsis queried live from SQLite via zero-copy attachment.historical_pricesis streamed directly from Parquet files on disk.- DuckDBβs vectorized query optimizer executes the join in a single pipeline without loading either dataset fully into RAM.