Crypto and Stablecoin Liquidity Pulse

Executed Notebook

This notebook asks whether BTC/ETH price residuals line up with current stablecoin liquidity context. It is a market-structure read, not a trading model.

The output is a CoinGecko source card, price decomposition, edge-trimmed residual events, and a current DeFiLlama stablecoin chain context table.

In [1]
from pathlib import Path
import os

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from examples.hot_trends.data import (
    HotTrendDataError,
    append_real_snapshot,
    build_arxiv_monthly_counts,
    fetch_coingecko_market_chart,
    fetch_defillama_stablecoin_chains,
    fetch_github_repo_metadata,
    fetch_github_stargazers,
    fetch_huggingface_models,
    fetch_wikipedia_pageviews,
    source_audit_table,
)
from examples.hot_trends.decomposition import (
    component_summary,
    decompose_table,
    editorial_priority,
    residual_event_table,
)
from examples.hot_trends.scoring import article_publication_phrasing

pd.set_option("display.max_columns", 80)
pd.set_option("display.max_rows", 80)
plt.rcParams.update({"axes.grid": True})

CACHE_DIR = Path("examples/hot_trends/cache")
OUTPUT_DIR = Path("examples/hot_trends/outputs")
CACHE_DIR.mkdir(parents=True, exist_ok=True)
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)

def save_table(df, name):
    path = OUTPUT_DIR / f"{name}.csv"
    df.to_csv(path, index=False)
    print(f"saved: {path.as_posix()}")

1. Fetch BTC and ETH market charts

In [2]
coins = ["bitcoin", "ethereum"]
frames = [fetch_coingecko_market_chart(c, days=365) for c in coins]
prices = pd.concat(frames, ignore_index=True)
prices.head(20)

2. Source card and price audit

In [3]
audit = source_audit_table(prices, value_col="price", entity_col="coin_id", time_col="date")
source_card = pd.DataFrame([{
    "source": "CoinGecko API",
    "endpoint": "https://api.coingecko.com/api/v3/coins/{coin_id}/market_chart",
    "access_date": pd.Timestamp.today().date().isoformat(),
    "query_params": f"coins={','.join(coins)}; vs_currency=usd; days=365",
    "time_range": f"{prices['date'].min()} to {prices['date'].max()}",
    "cache_path": "not cached; outputs saved to examples/hot_trends/outputs",
    "interpretation_scope": "public BTC/ETH price history for market-structure context; not a trading signal",
}])
display(source_card)
audit

3. Decompose crypto price series

In [4]
components = decompose_table(prices, entity_col="coin_id", time_col="date", value_col="price", method="MA_BASELINE", period=7, trend_window=21, transform="log")
summary = editorial_priority(component_summary(components, entity_col="coin_id", time_col="date"), entity_col="coin_id")
summary

Visualization: crypto price components

The left panels plot transformed observed price and trend by coin. The right panels plot residuals from the smooth baseline. Large bars mark dates for follow-up research; they are not entry or exit rules.

In [5]
coins_to_plot = summary["coin_id"].tolist()
fig, axes = plt.subplots(len(coins_to_plot), 2, figsize=(11, max(3.0, 2.6 * len(coins_to_plot))), squeeze=False)
for row, coin_id in enumerate(coins_to_plot):
    panel = components.loc[components["coin_id"].eq(coin_id)].sort_values("date").copy()
    panel["date"] = pd.to_datetime(panel["date"])
    axes[row, 0].plot(panel["date"], panel["observed"], label="observed", linewidth=1.6)
    axes[row, 0].plot(panel["date"], panel["trend"], label="trend", linewidth=1.8)
    axes[row, 0].set_title(coin_id)
    axes[row, 1].bar(panel["date"], panel["residual"], color=np.where(panel["residual"] >= 0, "tab:red", "tab:blue"), width=1.0)
    axes[row, 1].set_title("residual")
axes[0, 0].legend(loc="best")
plt.tight_layout()
plt.show()

4. Residual events

In [6]
events = residual_event_table(components, entity_col="coin_id", time_col="date", top_n=20, trim_edges=21)
events

5. Fetch current stablecoin context from DeFiLlama

This cell reads the current DeFiLlama stablecoin endpoint schema and records the table used for the liquidity context. It does not measure historical stablecoin-supply change.

In [7]
stablecoin_source_card = pd.DataFrame([{
    "source": "DeFiLlama stablecoin API",
    "endpoint": "https://stablecoins.llama.fi/stablecoins?includePrices=true",
    "access_date": pd.Timestamp.today().date().isoformat(),
    "query_params": "includePrices=true",
    "time_range": "current endpoint snapshot",
    "cache_path": "not cached; outputs saved to examples/hot_trends/outputs",
    "interpretation_scope": "current stablecoin chain supply context; not executable liquidity or a trading signal",
}])
stable_chains = fetch_defillama_stablecoin_chains()
display(stablecoin_source_card)
stable_chains.head(20)

Visualization: current stablecoin chain context

The x-axis is current pegged USD by chain from DeFiLlama. Use it to size the liquidity backdrop around BTC/ETH residual dates; do not read it as historical flow or available execution depth.

In [8]
def _pegged_usd(value):
    if isinstance(value, dict):
        return float(value.get("peggedUSD") or 0.0)
    return float(value or 0.0)

stable_context = stable_chains.assign(pegged_usd=stable_chains["totalCirculatingUSD"].map(_pegged_usd))
stable_context = stable_context.sort_values("pegged_usd", ascending=False).head(15).sort_values("pegged_usd")
ax = stable_context.plot(kind="barh", x="name", y="pegged_usd", figsize=(9, 5), color="tab:green", legend=False, title="Top stablecoin chains by pegged USD")
ax.set_xlabel("pegged USD")
ax.set_ylabel("")
plt.tight_layout()
plt.show()

6. Publication language

In [9]
phrasing = article_publication_phrasing()
phrasing
In [10]
save_table(source_card, "06_coingecko_source_card")
save_table(stablecoin_source_card, "06_defillama_source_card")
save_table(audit, "06_crypto_price_audit")
save_table(summary, "06_crypto_price_summary")
save_table(events, "06_crypto_price_residual_events")
save_table(stable_chains, "06_defillama_stablecoin_context")
save_table(phrasing, "06_crypto_publication_phrasing")