Skip to main content

coinlytics

PyPI version Python versions License CI

Python library for crypto portfolio analytics and market data — sits above the coinbasis cost-basis engine and handles all networking, caching, and analytics an app needs to run.

I built coinlytics as the data and analytics layer for a multi-tier crypto tracker ecosystem. It provides a resilient CoinGecko price client (keyless by default, automatic keyed fallback on HTTP 429, exponential backoff, TTL on-disk cache, and offline last-good serving), tax-aware portfolio rebalancing that simulates sells through coinbasis to estimate HIFO realized gains, daily portfolio value/P&L reconstruction by replaying the transaction ledger, performance metrics via coinbasis.stats, staking yield analytics via DefiLlama, and a news sentiment feed sourced from RSS and CryptoPanic. The package is intentionally minimal — it depends only on requests and coinbasis, with no ML or heavy analytics libraries.

Features

  • Resilient CoinGecko client — tries the public keyless endpoint first; on HTTP 429 automatically retries with a configured Demo or Pro API key (routing the correct base URL and auth header); exponential backoff with Retry-After header support; TTL on-disk JSON cache (atomic writes); offline last-good fallback with PriceBook.stale flag.
  • MockClient — satisfies the same PriceSource protocol as the real client; deterministic, no network; a fail_ids set exercises error-handling paths without mocking requests.
  • Tax-aware rebalancing — Band and Full strategies; drift calculation vs. target weights (equal, market-cap, or custom); HIFO realized-gain estimate for each proposed sell, computed by appending a simulated Sell to a throwaway coinbasis.Portfolio and reading the gain delta.
  • Historical P&L reconstruction — replays the full transaction ledger up to each target date using coinbasis.Portfolio.from_transactions, then values holdings at per-coin historical prices.
  • Performance metrics — daily Snapshot dataclass; delegates volatility, Sharpe ratio, max drawdown, and cumulative return to coinbasis.stats.
  • DefiLlama staking APY — fetches pool yields for a list of symbols; selects the highest-TVL exact-match pool per symbol.
  • News + sentiment — fetch_rss and fetch_cryptopanic with a DOCTYPE entity-expansion guard (stdlib only, no defusedxml); naive keyword-lexicon sentiment classification (bullish/bearish/neutral) using whole-word regex matching.
  • Analytics helpers — Pearson correlation, correlation matrix, portfolio volatility, annualized volatility.

Tech Stack

Layer Choice
Language Python >= 3.10
Cost-basis engine coinbasis >= 0.1, < 0.2
HTTP requests >= 2.28, < 3
XML parsing xml.etree.ElementTree (stdlib)
Money math decimal.Decimal throughout
Build setuptools >= 68
Lint / format ruff
Tests pytest

Getting Started

pip install coinlytics

For local development against an unpublished coinbasis:

pip install -e ../coinbasis-py   # local coinbasis first
pip install -e ".[dev]"          # coinlytics + pytest + ruff

Fetch current prices (keyless, no API key needed)

from coinlytics import CoinGeckoClient, CoinGeckoConfig

cfg = CoinGeckoConfig(cache_dir="~/.cache/coinlytics")
client = CoinGeckoClient(cfg)
pb = client.prices(["bitcoin", "ethereum"])

print(pb.quotes["bitcoin"].price)   # decimal.Decimal
print(pb.stale)                      # True if served from offline cache
prices_map = pb.prices_map()         # dict[str, Decimal] for coinbasis.Portfolio.valuation()

With a Demo API key (keyed fallback on 429)

cfg = CoinGeckoConfig(
    api_key="your-demo-key",
    plan="demo",
    cache_dir="~/.cache/coinlytics",
    cache_ttl=120,
)
client = CoinGeckoClient(cfg)

Tax-aware rebalancing

from decimal import Decimal
from coinlytics import compute_trades, target_weights, RebalanceStrategy
import coinbasis

# portfolio is a coinbasis.Portfolio built from your ledger
weights = target_weights("equal", ["bitcoin", "ethereum"])
plan = compute_trades(
    current_values={"bitcoin": Decimal("70000"), "ethereum": Decimal("30000")},
    target_weights_map=weights,
    prices={"bitcoin": Decimal("50000"), "ethereum": Decimal("3000")},
    strategy=RebalanceStrategy.BAND,
    band=Decimal("0.05"),
    portfolio=portfolio,   # optional: attaches TaxEstimate to sells
)
for action in plan.actions:
    print(action.asset, action.side, action.amount_usd)
    if action.tax:
        print("  estimated HIFO gain:", action.tax.realized_gain)

Historical portfolio value/P&L

from coinlytics import reconstruct_series

series = reconstruct_series(
    txs=portfolio.transactions,
    price_by_coin_date={"bitcoin": {"2024-01-01": 42000.0, "2024-01-02": 43500.0}},
    dates=["2024-01-01", "2024-01-02"],
)
for day in series:
    print(day["date"], day["value"], day["pl"])

News sentiment

from coinlytics import fetch_rss, filter_items, sentiment_summary, keywords_for

items = fetch_rss("https://cointelegraph.com/rss")
btc_items = filter_items(items, keywords_for("bitcoin", {}))
summary = sentiment_summary(btc_items)
print(summary["overall"])   # 'bullish' | 'bearish' | 'neutral'

Examples

Runnable scripts live in examples/ — one self-contained script per file. Run any of them with python examples/<name>.py.

The offline examples need no network and no API key:

Example What it shows
mock_client.py MockClient as a drop-in PriceSource — prices, history, market caps, sparklines, and the fail_ids error path. Fully offline.
rebalance.py Tax-aware rebalancing: builds a coinbasis ledger, computes trades toward equal weights, and attaches a HIFO TaxEstimate to each sell.
performance.py Daily Snapshot history, dedup_append, and metrics (volatility, Sharpe, max drawdown, cumulative return) via coinbasis.stats.
history.py Daily value/P&L reconstruction by replaying a ledger with reconstruct_series, plus point-in-time holdings_as_of.
staking.py Effective APYs (API match vs. manual fallback), projected yield, rewards summary, and combined P&L.
news.py Keyword filtering (whole-word) and lexicon sentiment (classify_sentiment, sentiment_summary) over news-item dicts.

The two live-price examples hit the network (and are clearly marked); they guard their network calls so they print a friendly message rather than crash when offline:

Example What it shows
prices_keyless.py Real CoinGeckoClient against the public keyless endpoint. Needs internet.
prices_with_key.py Real CoinGeckoClient with a Demo API key (keyed fallback on HTTP 429). Needs internet and COINGECKO_API_KEY.

The offline examples are exercised by tests/test_examples.py; the network ones are skipped there.

Development

# Run tests
pytest

# Lint
ruff check src/ tests/

# Build a distribution
python -m build

Project Structure

coinlytics-py/
├── src/
│   └── coinlytics/
│       ├── __init__.py          # public re-exports
│       ├── errors.py            # typed exception hierarchy
│       ├── analytics.py         # correlation, portfolio volatility, annualize
│       ├── defillama.py         # DefiLlama APY fetcher
│       ├── history.py           # ledger-replay P&L reconstruction
│       ├── news.py              # keyword filter + lexicon sentiment
│       ├── perf.py              # Snapshot, PerfMetrics, metrics()
│       ├── rebalance.py         # Band/Full strategies + tax estimate
│       ├── rss.py               # RSS + CryptoPanic fetchers
│       ├── staking.py           # effective APY, projected yield, rewards summary
│       └── prices/
│           ├── __init__.py
│           ├── client.py        # CoinGeckoClient (keyless→keyed→cache→offline)
│           ├── cache.py         # DiskCache (TTL, atomic writes)
│           ├── mock.py          # MockClient (PriceSource protocol, no network)
│           └── models.py        # Quote, PriceBook, HistoryPoint, PriceSource
├── tests/
│   ├── conftest.py
│   ├── test_client.py
│   ├── test_cache.py
│   ├── test_mock_client.py
│   ├── test_rebalance.py
│   ├── test_history.py
│   ├── test_perf.py
│   ├── test_staking.py
│   ├── test_defillama.py
│   ├── test_rss.py
│   ├── test_news.py
│   └── test_analytics.py
├── pyproject.toml
└── README.md

License

MIT OR Apache-2.0

Author

Jacob Kanfer — github.com/Technical-1

Release files for coinlytics 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for coinlytics 0.1.0
File Size Uploaded
coinlytics-0.1.0.tar.gz 56.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for coinlytics 0.1.0
File Interpreter ABI Platform
coinlytics-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 90.3 kB

Release files / coinlytics-0.1.0.tar.gz

Download URL coinlytics-0.1.0.tar.gz
Size 56.8 kB
Tags Source
SHA-256 checksum
How to use checksums
46751a6f85e591758a91453f90a5547e3dfd9fbce047083f370cf40d38b1853f
BLAKE2b-256 checksum
How to use checksums
53161e80d0fbe307c2e3ae002cc4fb93ad62d0351dea3df09eacfd11ed9db1bb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 4, 2026.

Transparency log

Release files / coinlytics-0.1.0-py3-none-any.whl

Download URL coinlytics-0.1.0-py3-none-any.whl
Size 33.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2880aeedbc6357b0e5dfbe87e2560fa78850e7d89b807116b82c14b8ec531dc2
BLAKE2b-256 checksum
How to use checksums
4441a247733ca9bbaf7df6e121182c120c3e50025d448ed3beff5babe1f244aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release 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