Avi-L commited on
Commit
41ebda5
·
verified ·
1 Parent(s): 3ea2315

coinmetrics daily panel ingest

Browse files
Files changed (1) hide show
  1. ingest2.py +94 -0
ingest2.py ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Ingest daily price panel for 6-8 major crypto assets from coinmetrics.
2
+
3
+ Source: coinmetrics-community CSVs on GitHub (PriceUSD = volume-weighted
4
+ index across exchanges). Long daily history (btc 2010+, ltc/xrp 2013+,
5
+ eth 2015+) — this is the statistical-power lever for the DSR gate.
6
+
7
+ Output (uploaded to Avi-L/crypto-quant-eval-data):
8
+ panel_daily_close.parquet wide close-price panel, index=date, cols=symbols
9
+ panel_daily_meta.json per-asset start dates, obs counts, ADV assumptions
10
+ manifest2.json sha256 outputs + sources
11
+ """
12
+ import hashlib
13
+ import io
14
+ import json
15
+ import tempfile
16
+ import urllib.request
17
+ from pathlib import Path
18
+
19
+ import pandas as pd
20
+ from huggingface_hub import HfApi
21
+
22
+ DEST = "Avi-L/crypto-quant-eval-data"
23
+ BASE = "https://raw.githubusercontent.com/coinmetrics/data/master/csv/{}.csv"
24
+ # majors with long daily history; ADV = realistic combined spot+perp
25
+ # notional/day used by the impact model (conservative, 2025-26 orderbook)
26
+ ASSETS = {
27
+ "BTC": 20e9, "ETH": 10e9, "LTC": 1.0e9, "XRP": 1.5e9,
28
+ "ADA": 0.5e9, "DOGE": 1.0e9, "ETC": 0.3e9, "DASH": 0.1e9,
29
+ }
30
+
31
+ MANIFEST = {"sources": {}, "outputs": {}, "assets": {}}
32
+
33
+
34
+ def sha256_file(p: Path) -> str:
35
+ h = hashlib.sha256()
36
+ with open(p, "rb") as f:
37
+ for chunk in iter(lambda: f.read(1 << 20), b""):
38
+ h.update(chunk)
39
+ return h.hexdigest()
40
+
41
+
42
+ def load_asset(sym: str) -> pd.Series:
43
+ url = BASE.format(sym.lower())
44
+ print(f"[ingest] fetching {url}", flush=True)
45
+ with urllib.request.urlopen(url, timeout=120) as r:
46
+ df = pd.read_csv(io.BytesIO(r.read()))
47
+ if "time" not in df or "PriceUSD" not in df:
48
+ raise ValueError(f"{sym}: missing time/PriceUSD columns")
49
+ s = pd.Series(df["PriceUSD"].values,
50
+ index=pd.to_datetime(df["time"], utc=True),
51
+ name=sym).dropna()
52
+ return s[s.index >= "2013-01-01"]
53
+
54
+
55
+ def main() -> None:
56
+ with tempfile.TemporaryDirectory() as tmp:
57
+ out = Path(tmp)
58
+ panel = {}
59
+ for sym, adv in ASSETS.items():
60
+ try:
61
+ s = load_asset(sym)
62
+ except Exception as e:
63
+ print(f"[ingest] {sym} FAILED: {e}", flush=True)
64
+ continue
65
+ panel[sym] = s
66
+ MANIFEST["assets"][sym] = {
67
+ "start": str(s.index[0].date()), "obs": int(len(s)), "adv_usd": adv,
68
+ }
69
+ print(f"[ingest] {sym}: {len(s):,} days from {s.index[0].date()}",
70
+ flush=True)
71
+ if "BTC" not in panel:
72
+ raise RuntimeError("no BTC data — aborting")
73
+ close = pd.DataFrame(panel).sort_index()
74
+ close.index.name = "date"
75
+ p = out / "panel_daily_close.parquet"
76
+ close.to_parquet(p)
77
+ MANIFEST["outputs"][p.name] = {"sha256": sha256_file(p),
78
+ "rows": len(close), "cols": close.shape[1]}
79
+ meta = out / "panel_daily_meta.json"
80
+ meta.write_text(json.dumps(MANIFEST, indent=2))
81
+ MANIFEST["sources"]["coinmetrics-community CSVs"] = BASE.format("btc")
82
+ meta.write_text(json.dumps(MANIFEST, indent=2))
83
+
84
+ api = HfApi()
85
+ for f in (p, meta):
86
+ api.upload_file(path_or_fileobj=str(f), path_in_repo=f.name,
87
+ repo_id=DEST, repo_type="dataset",
88
+ commit_message="daily multi-asset price panel")
89
+ print(f"[ingest] panel: {close.shape[0]:,} days x "
90
+ f"{close.shape[1]} assets, uploaded", flush=True)
91
+
92
+
93
+ if __name__ == "__main__":
94
+ main()