marketgoblin
Download, store, and load financial market data — fast, without fuss.
Features
-
Multi-dataset fetch & persist
Download OHLCV, shares-outstanding, or dividends by symbol and date range via a
Datasetenum. Whensave_pathis set, data is automatically sliced into monthly Parquet files on disk. -
Lazy by default
Built on Polars. Every data path returns a
pl.LazyFrame— nothing is computed until you call.collect(). -
Batch fetching
fetch_many()uses aThreadPoolExecutorwith a token-bucket rate limiter. Failed symbols are logged and skipped — they never crash the batch. -
Pluggable sources
Subclass
BaseSource, implement one method, register in one line. Ships withYahooSourceandTiingoSourceout of the box. -
Reliable by default
YahooSourceretries transient failures with exponential backoff. Writes are atomic (.tmprename). JSON sidecars record metadata per slice. -
Predictable storage layout
Uniform across datasets:
{save_path}/{provider}/{dataset}/{SYMBOL}/{SYMBOL}_{YYYY-MM}.pq. OHLCV adjusted + raw share one file, distinguished by theis_adjustedcolumn. Every slice is inspectable and portable with any Parquet reader.
Quick start
import polars as pl
from marketgoblin import MarketGoblin
goblin = MarketGoblin(provider="yahoo", save_path="./data")
# OHLCV is a tidy stacked frame — each day appears twice
# (is_adjusted=True / False). Filter to pick a variant.
lf = goblin.fetch("AAPL", "2024-01-01", "2024-03-31", parse_dates=True)
print(lf.filter(pl.col("is_adjusted")).collect())
from marketgoblin import MarketGoblin
goblin = MarketGoblin(provider="yahoo", save_path="./data")
results = goblin.fetch_many(
["AAPL", "MSFT", "GOOGL", "NVDA"],
start="2024-01-01",
end="2024-03-31",
max_workers=4,
requests_per_second=2.0,
)
for symbol, lf in results.items():
print(f"{symbol}: {lf.collect().height} rows")
from marketgoblin import Dataset, MarketGoblin
# Tiingo covers the full catalog (splits, daily & quarterly fundamentals).
# Reads its key from api_key= or the TIINGO_API_KEY env var.
goblin = MarketGoblin(provider="tiingo", save_path="./data")
statements = goblin.fetch(
"AAPL",
"2023-01-01",
"2024-03-31",
dataset=Dataset.FUNDAMENTALS_STATEMENTS,
parse_dates=True,
)
print(statements.collect())
Data conventions
| Property | Value |
|---|---|
| Date on disk | int32 YYYYMMDD (e.g. 20240101) — use parse_dates=True to get pl.Date |
| OHLC columns | float32 |
| Volume column | int64 |
is_adjusted column |
bool (OHLCV only — distinguishes adjusted vs raw rows) |
| Shares column | int64 |
| Dividend column | float32 |
| Parquet path | {save_path}/{provider}/{dataset}/{SYMBOL}/{SYMBOL}_{YYYY-MM}.pq (uniform across datasets) |
| JSON sidecar | Same path, .json — row count, date range, per-dataset stats (OHLCV also records has_adjusted/has_raw and missing trading days) |
Datasets
| Dataset | Providers | Notes |
|---|---|---|
Dataset.OHLCV |
yahoo, tiingo |
Daily open/high/low/close/volume. Tidy stacked: each day appears twice with is_adjusted=True/False. Adjusted Open/High/Low are derived locally from Adj Close / Close (zero numerical drift vs auto_adjust=True, half the network calls). |
Dataset.SHARES |
yahoo, tiingo |
Shares outstanding — sparse, corporate-action-driven cadence. Deduplicated to one row per day (last value wins). |
Dataset.DIVIDENDS |
yahoo, tiingo |
Cash dividend events — typically quarterly. Filtered to the requested [start, end] range. |
Dataset.SPLITS |
tiingo |
Forward/reverse split events as a split_factor multiplier. |
Dataset.FUNDAMENTALS_DAILY |
tiingo |
Daily market cap, enterprise value, and valuation ratios. Paid endpoint. |
Dataset.FUNDAMENTALS_STATEMENTS |
tiingo |
Full quarterly income statement, balance sheet, cash flow & overview — every line item in both as-reported and restated variants. Paid endpoint. |
See Providers & Capabilities for the full matrix.