Skip to main content

LLM-oriented narration and compression for time series data

Project description

narrata

narrata turns OHLCV price series into compact, deterministic text summaries optimized for LLM context. It has two goals:

  1. Make agents understand time series. A raw data dump doesn't give an LLM the context it needs — regime, trend, support/resistance, indicator state. narrata extracts that structure and renders it as natural-language text an agent can act on.
  2. Minimal token usage. Every token in a prompt costs latency and money. narrata keeps output as compact as possible — sections that cannot be computed (short history, missing columns) are silently omitted rather than padded with placeholder text.

Installation

pip install narrata

Install optional backends:

pip install "narrata[all]"

Requires Python 3.11+ and pandas 2.0+.

Quickstart

narrate(...) takes a pandas OHLCV DataFrame with a datetime index.

import yfinance as yf
from narrata import narrate

df = yf.download("AAPL", period="1y", multi_level_index=False)
print(narrate(df, ticker="AAPL"))

Column names are case-insensitive (close works as well as Close), Adj Close is preferred over raw Close when both exist, and Volume is optional. Close-only data works too — patterns and candlestick sections are omitted automatically, everything else runs normally. For short histories or missing columns, narrata keeps running and silently omits sections it cannot compute — no wasted tokens on placeholder text.

Example output:

AAPL (251 pts, daily): ▅▄▃▁▂▁▁▂▂▂▄▄▆▇▇██▆▆▆
Date range: 2025-02-14 to 2026-02-13
Range: [171.67, 285.92]  Mean: 235.06  Std: 28.36
Start: 243.54  End: 255.78  Change: +5.03%
Regime: Uptrend since 2025-05-07 (low volatility)
RSI(14): 39.6 (neutral-bearish)  MACD: bearish crossover 0 days ago
BB: lower half
SMA 50/200: golden cross
Volume: 0.94x 20-day avg (average)
Volatility: 84th percentile (high)
SAX(16): ecabbabbdegghhhg
Candlestick: Inside Bar on 2026-02-10
Support: 201.77 (26 touches), 208.38 (23 touches)  Resistance: 270.88 (24 touches), 257.57 (22 touches)

Fallback vs extras (same input)

Using the same static real-market MSFT dataset (251 daily points, yfinance fixture):

Fallback-only (pip install narrata):

MSFT (251 pts, daily): ▂▁▁▁▃▄▅▇▇█▇███▇▆▅▆▆▂
Date range: 2025-02-14 to 2026-02-13
Range: [354.56, 542.07]  Mean: 466.98  Std: 49.62
Start: 408.43  End: 401.32  Change: -1.74%
Regime: Downtrend since 2026-01-29 (high volatility)
RSI(14): 32.4 (neutral-bearish)  MACD: bearish crossover 11 days ago
BB: lower half
SMA 50/200: death cross 17 days ago
Volume: 0.74x 20-day avg (below average)
Volatility: 94th percentile (extremely high)
SAX(16): aaabdfggggggffdb
Candlestick: Inside Bar on 2026-02-13
Support: 393.67 (15 touches), 378.77 (8 touches)  Resistance: 510.83 (34 touches), 481.63 (21 touches)

With extras (pip install "narrata[all]"):

MSFT (251 pts, daily): ▂▁▁▁▃▄▅▇▇█▇███▇▆▅▆▆▂
Date range: 2025-02-14 to 2026-02-13
Range: [354.56, 542.07]  Mean: 466.98  Std: 49.62
Start: 408.43  End: 401.32  Change: -1.74%
Regime: Ranging since 2025-02-18 (low volatility)
RSI(14): 32.4 (neutral-bearish)  MACD: bearish crossover 11 days ago
BB: lower half
SMA 50/200: death cross 17 days ago
Volume: 0.74x 20-day avg (below average)
Volatility: 94th percentile (extremely high)
SAX(16): aaabdefggggggfed
Candlestick: Inside Bar on 2026-02-13
Support: 393.67 (15 touches), 378.77 (8 touches)  Resistance: 510.83 (34 touches), 481.63 (21 touches)

Crypto data

from narrata import from_ccxt, from_coingecko, narrate

# ccxt (Binance, Coinbase, Kraken, etc.)
df = from_ccxt(exchange.fetch_ohlcv("BTC/USDT", "15m"), ticker="BTC/USDT")

# CoinGecko (close-only)
df = from_coingecko(cg.get_coin_market_chart_by_id(...), ticker="BTC")

# yfinance — works directly, no adapter needed

Compare two periods

from narrata import compare

df_q1 = df["2025-01":"2025-03"]
df_q2 = df["2025-04":"2025-06"]
print(compare(df_q1, df_q2, ticker="AAPL"))

Produces a compact diff narrative with arrows showing changes in price, regime, indicators, symbolic encoding, and support/resistance between the two periods.

CLI

# CSV, TSV, or Parquet (auto-detected from extension)
narrata prices.csv --ticker AAPL
narrata prices.tsv --ticker AAPL
narrata prices.parquet --ticker AAPL

# Pipe from stdin (use --input-format for non-CSV)
cat prices.tsv | narrata --input-format tsv --ticker AAPL

# Output formats: plain, markdown_kv, toon, json
narrata prices.csv --format json

# Precision and ASTRIDE encoding
narrata prices.csv --precision 0 --symbolic-method astride

# Intraday data (frequency auto-detected, or explicit for patchy data)
narrata intraday_15m.csv --ticker AAPL --currency '$'
narrata intraday_15m.csv --ticker AAPL --frequency 15min

# Compare two periods
narrata compare q1.csv q2.csv --ticker AAPL

Run narrata --help for all options.

Digit Splitting for LLM Robustness

digit_tokenize(...) can help when your downstream model is sensitive to dense numeric strings.

Use it when you have many prices, percentages, or long decimals in prompt context.

from narrata import digit_tokenize

print(digit_tokenize("Price 171.24, move +3.2%"))
# <digits-split>
# Price 1 7 1 . 2 4 , move + 3 . 2 %

Intraday awareness

narrata auto-detects sub-daily frequencies (1min, 5min, 15min, 30min, hourly) and scales indicator parameters so lookback windows cover the same calendar-time horizons as daily mode. For example, on 15-minute bars SMA crossover uses 10/40 instead of 50/200, and volume lookback uses 26 bars (~1 trading day) instead of 20 days. Output labels adapt automatically ("SMA 10/40", "26-bar avg").

For patchy or unevenly-spaced data, pass the frequency explicitly: narrate(df, frequency="15min") or --frequency 15min on the CLI. Use "irregular" for data with no fixed interval — units display as "bars" instead of "days".

Features

  • Input validation for OHLCV DataFrames
  • Summary analysis with date range context
  • Regime classification (Uptrend / Downtrend / Ranging)
  • Intraday-aware indicators — auto-scaled defaults for sub-daily bars
  • RSI and MACD interpretation
  • Bollinger Band and moving average crossover descriptions
  • Volatility and volume context
  • SAX symbolic encoding
  • ASTRIDE adaptive symbolic encoding (with ruptures)
  • Pattern and candlestick detection
  • Support/resistance extraction
  • Sparkline generation
  • Output formatting (plain, markdown_kv, toon, json)

FAQ

Is narrata redundant if I already use OpenBB, yfinance, or another data SDK?

No. narrata is complementary. It sits on top of your data access layer and converts OHLCV data into concise, LLM-ready narrative text.

Does narrata call an LLM or provide LLM endpoints?

No. narrata is a pure Python library with deterministic, programmatic analysis and narration. It does not call LLM APIs.

Citation

If you use narrata in research or public projects, cite this package using CITATION.cff.

Project details


Download files

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

Source Distribution

narrata-0.1.3.tar.gz (73.9 kB view details)

Uploaded Source

Built Distribution

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

narrata-0.1.3-py3-none-any.whl (41.3 kB view details)

Uploaded Python 3

File details

Details for the file narrata-0.1.3.tar.gz.

File metadata

  • Download URL: narrata-0.1.3.tar.gz
  • Upload date:
  • Size: 73.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for narrata-0.1.3.tar.gz
Algorithm Hash digest
SHA256 c6ae2b6b0303e159c5815ecac059120fa53d069456335860d96c0333d15c0878
MD5 c91c47a1e4b13cdf031be70777646bc4
BLAKE2b-256 b2d102b1c988252723d28433f185bb16783d55e69783f4d14f0bd1ca45204b3b

See more details on using hashes here.

Provenance

The following attestation bundles were made for narrata-0.1.3.tar.gz:

Publisher: release.yml on marcinmiklitz/narrata

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

File details

Details for the file narrata-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: narrata-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 41.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for narrata-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 803177409b8db909dc76386c152423bb25d0c3e91e6c345c8590c6c3432560f4
MD5 bb2b0274d7266d750d2639f4fbebf43b
BLAKE2b-256 06e1c1714c5e3bf2178e78ced8ed96578143497cc97536ead3009fae92e4d87d

See more details on using hashes here.

Provenance

The following attestation bundles were made for narrata-0.1.3-py3-none-any.whl:

Publisher: release.yml on marcinmiklitz/narrata

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page