quantlab.dataset.sharadar.stock#

Sharadar daily price panel with permatickers as the symbol axis.

Sharadar is the primary US-equity vendor (ADR 0023). Its price tables (SEP for stocks) are keyed by ticker, and when a delisted company’s ticker is reused Sharadar renames that company’s whole history to a suffixed ticker. The ticker is therefore not a stable axis. The permaticker, Sharadar’s unchanging integer id of one share class, is: it appears only in the TICKERS table, which maps each (table, ticker) to its permaticker.

SharadarStockDataset converts the raw tier (the vendor’s own rows, pulled by quantlab.acquisition.sharadar.client into parquet under <download-dir>/sharadar/) into a dense (timestamp, symbol) Zarr panel whose symbol coordinate is the int64 permaticker. Each raw row is mapped through the TICKERS rows of its own table, so a ticker of a fund never maps a stock, and as of its raw file’s own pull, so a security whose ticker changed after a file was pulled keeps its rows (quantlab.dataset.sharadar.permatickers: the file’s TICKERS snapshot, current TICKERS, the ACTIONS ticker changes, then the store’s ticker sidecar). The conversion refuses a ticker TICKERS maps to two permatickers, and two rows of one permaticker on one date, rather than guess which company a row belongs to. A row no permaticker is found for is left out with a warning and listed in <store>.unmapped.json (unmapped_path()), so a daily update completes; those bars are missing from the store.

The panel holds raw (unadjusted) prices, so a later dividend or split never rewrites a stored row:

  • close is SEP’s closeunadj;

  • open/high/low are SEP’s split-adjusted values times closeunadj / close, and volume is SEP’s split-adjusted volume divided by that ratio (Sharadar’s own imputation of the raw values).

Sharadar’s adjusted columns (close and the other split-adjusted values, closeadj) and lastupdated are not stored: the vendor rewrites them over the whole history on every ex-date. quantlab builds its own adjusted prices instead, from the raw prices and the dividend, spinoff-value and split events of the ACTIONS table, with the CRSP panel’s convention and names (adjOpen, adjHigh, adjLow, adjClose, adjVolume, divCash, splitFactor; see SharadarStockDataset._adjust). The panel therefore carries the same twelve daily variables as a CRSP or Tiingo panel, and a factor, label or backtest reads it without knowing the vendor. Like a CRSP panel it also carries cumfacshr, the cumulative share adjustment factor: 1.0 on each permaticker’s first stored bar and divided by splitFactor on every bar since, so cumfacshr[t-1] / cumfacshr[t] == splitFactor[t] with cumfacshr[t-1] the permaticker’s last earlier stored value. Only such ratios are meaningful; an executor books a holder’s split from them. A bar without a fill price is untradable (the MarketDataset default), and so is a bar Sharadar carries forward through a trading halt: volume 0 and the previous close repeated (SharadarStockDataset.tradable_bars). delisting_bars is the default: a delisted security is settled at its last close, with no delisting return imputed (Sharadar gives none).

Every conversion, an update included, also writes the ticker sidecar <store>.sharadar_tickers.json beside the store from TICKERS and ACTIONS (quantlab.dataset.sharadar.tickers), and ticker_lookup() reads it, so a backtest shows each permaticker as the ticker and company in use that day.

Examples#

>>> config = SharadarDatasetConfig(
...     zarr_file_path="/data/market/sharadar/sharadar_sep_1d/sharadar_sep_1d.zarr",
...     raw_data_dir_path="/data/downloads/sharadar",
... )
>>> SharadarStockDataset(config).from_raw_data().save()
>>> panel = SharadarStockDataset(config).panel("2024-01-02", "2024-01-05")
>>> sorted(panel.data_vars)
['adjClose', 'adjHigh', 'adjLow', 'adjOpen', 'adjVolume', 'anomaly_flag', 'close', 'cumfacshr', 'divCash', 'high', 'low', 'open', 'splitFactor', 'volume']

Classes

SharadarStockDataset

Dense daily panel of raw OHLCV from a Sharadar price table, keyed by permaticker.