crypto-quant-eval / ingest2.py
Avi-L's picture
coinmetrics daily panel ingest
41ebda5 verified
Raw History Blame Contribute Delete
3.55 kB
"""Ingest daily price panel for 6-8 major crypto assets from coinmetrics.
Source: coinmetrics-community CSVs on GitHub (PriceUSD = volume-weighted
index across exchanges). Long daily history (btc 2010+, ltc/xrp 2013+,
eth 2015+) — this is the statistical-power lever for the DSR gate.
Output (uploaded to Avi-L/crypto-quant-eval-data):
panel_daily_close.parquet wide close-price panel, index=date, cols=symbols
panel_daily_meta.json per-asset start dates, obs counts, ADV assumptions
manifest2.json sha256 outputs + sources
"""
import hashlib
import io
import json
import tempfile
import urllib.request
from pathlib import Path
import pandas as pd
from huggingface_hub import HfApi
DEST = "Avi-L/crypto-quant-eval-data"
BASE = "https://raw.githubusercontent.com/coinmetrics/data/master/csv/{}.csv"
# majors with long daily history; ADV = realistic combined spot+perp
# notional/day used by the impact model (conservative, 2025-26 orderbook)
ASSETS = {
"BTC": 20e9, "ETH": 10e9, "LTC": 1.0e9, "XRP": 1.5e9,
"ADA": 0.5e9, "DOGE": 1.0e9, "ETC": 0.3e9, "DASH": 0.1e9,
}
MANIFEST = {"sources": {}, "outputs": {}, "assets": {}}
def sha256_file(p: Path) -> str:
h = hashlib.sha256()
with open(p, "rb") as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
def load_asset(sym: str) -> pd.Series:
url = BASE.format(sym.lower())
print(f"[ingest] fetching {url}", flush=True)
with urllib.request.urlopen(url, timeout=120) as r:
df = pd.read_csv(io.BytesIO(r.read()))
if "time" not in df or "PriceUSD" not in df:
raise ValueError(f"{sym}: missing time/PriceUSD columns")
s = pd.Series(df["PriceUSD"].values,
index=pd.to_datetime(df["time"], utc=True),
name=sym).dropna()
return s[s.index >= "2013-01-01"]
def main() -> None:
with tempfile.TemporaryDirectory() as tmp:
out = Path(tmp)
panel = {}
for sym, adv in ASSETS.items():
try:
s = load_asset(sym)
except Exception as e:
print(f"[ingest] {sym} FAILED: {e}", flush=True)
continue
panel[sym] = s
MANIFEST["assets"][sym] = {
"start": str(s.index[0].date()), "obs": int(len(s)), "adv_usd": adv,
}
print(f"[ingest] {sym}: {len(s):,} days from {s.index[0].date()}",
flush=True)
if "BTC" not in panel:
raise RuntimeError("no BTC data — aborting")
close = pd.DataFrame(panel).sort_index()
close.index.name = "date"
p = out / "panel_daily_close.parquet"
close.to_parquet(p)
MANIFEST["outputs"][p.name] = {"sha256": sha256_file(p),
"rows": len(close), "cols": close.shape[1]}
meta = out / "panel_daily_meta.json"
meta.write_text(json.dumps(MANIFEST, indent=2))
MANIFEST["sources"]["coinmetrics-community CSVs"] = BASE.format("btc")
meta.write_text(json.dumps(MANIFEST, indent=2))
api = HfApi()
for f in (p, meta):
api.upload_file(path_or_fileobj=str(f), path_in_repo=f.name,
repo_id=DEST, repo_type="dataset",
commit_message="daily multi-asset price panel")
print(f"[ingest] panel: {close.shape[0]:,} days x "
f"{close.shape[1]} assets, uploaded", flush=True)
if __name__ == "__main__":
main()