ledger: extract CoinGecko top-20 cryptos (2026-11-04) to CSV + MD + CHECK
This commit is contained in:
1 parent
086423c2be
commit
788fa71cd0
3 files changed
+177
No files matched your search
@@ -0,0 +1,21 @@
|
||||
rank,name,symbol,price_usd,market_cap_usd,market_cap_change_24h_pct,volume_24h_usd
|
||||
1,Bitcoin,btc,78382,1575893146452,1.49,31492703674
|
||||
2,Ethereum,eth,2316.73,283079436237,1.72,11509848251
|
||||
3,Tether,usdt,0.998969,178189851682,-0.39,49857500751
|
||||
4,BNB,bnb,699.49,91991216509,0.06,972490046
|
||||
5,XRP,xrp,1.28,81138041353,0.16,2367963367
|
||||
6,USDC,usdc,0.999448,70550799494,-0.41,13815706242
|
||||
7,Solana,sol,92.72,54727794168,-0.1,2778173808
|
||||
8,TRON,trx,0.318963,30309543786,-0.83,538095594
|
||||
9,Figure Heloc,figr_heloc,1.03,26844879741,-0.03,481114715
|
||||
10,Zcash,zec,1288.02,21925269847,6.86,1147674146
|
||||
11,Hyperliquid,hype,84.94,20335597447,0.32,1348530812
|
||||
12,Monero,xmr,641.9,12084828023,2.94,193676029
|
||||
13,Dogecoin,doge,0.074743,11704959032,-0.3,483661183
|
||||
14,USDS,usds,1.0,9576191536,-0.17,210065027
|
||||
15,WhiteBIT Coin,wbt,75.28,8934911929,1.31,133655260
|
||||
16,LEO Token,leo,9.32,8576829551,0.61,100555
|
||||
17,Chainlink,link,11.13,8531870409,-0.48,304608346
|
||||
18,Cardano,ada,0.189974,7138766905,-0.16,235438100
|
||||
19,Stellar,xlm,0.163071,5761475891,-1.36,135925538
|
||||
20,Bitcoin Cash,bch,274.04,5511420220,-0.88,146355359
|
||||
|
@@ -0,0 +1,28 @@
|
||||
# Top 20 Cryptocurrencies by Market Cap (USD)
|
||||
|
||||
Source: CoinGecko API `coins/markets` (2026-11-04), `vs_currency=usd`, `per_page=20`, sorted by `market_cap` desc.
|
||||
|
||||
| Rank | Name | Symbol | Price (USD) | Market Cap (USD) | 24h % | 24h Vol (USD) |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | Bitcoin | btc | 78,382.0000 | 1,575,893,146,452 | +1.49% | 31,492,703,674 |
|
||||
| 2 | Ethereum | eth | 2,316.7300 | 283,079,436,237 | +1.72% | 11,509,848,251 |
|
||||
| 3 | Tether | usdt | 0.9990 | 178,189,851,682 | -0.39% | 49,857,500,751 |
|
||||
| 4 | BNB | bnb | 699.4900 | 91,991,216,509 | +0.06% | 972,490,046 |
|
||||
| 5 | XRP | xrp | 1.2800 | 81,138,041,353 | +0.16% | 2,367,963,367 |
|
||||
| 6 | USDC | usdc | 0.9994 | 70,550,799,494 | -0.41% | 13,815,706,242 |
|
||||
| 7 | Solana | sol | 92.7200 | 54,727,794,168 | -0.10% | 2,778,173,808 |
|
||||
| 8 | TRON | trx | 0.3190 | 30,309,543,786 | -0.83% | 538,095,594 |
|
||||
| 9 | Figure Heloc | figr_heloc | 1.0300 | 26,844,879,741 | -0.03% | 481,114,715 |
|
||||
| 10 | Zcash | zec | 1,288.0200 | 21,925,269,847 | +6.86% | 1,147,674,146 |
|
||||
| 11 | Hyperliquid | hype | 84.9400 | 20,335,597,447 | +0.32% | 1,348,530,812 |
|
||||
| 12 | Monero | xmr | 641.9000 | 12,084,828,023 | +2.94% | 193,676,029 |
|
||||
| 13 | Dogecoin | doge | 0.0747 | 11,704,959,032 | -0.30% | 483,661,183 |
|
||||
| 14 | USDS | usds | 1.0000 | 9,576,191,536 | -0.17% | 210,065,027 |
|
||||
| 15 | WhiteBIT Coin | wbt | 75.2800 | 8,934,911,929 | +1.31% | 133,655,260 |
|
||||
| 16 | LEO Token | leo | 9.3200 | 8,576,829,551 | +0.61% | 100,555 |
|
||||
| 17 | Chainlink | link | 11.1300 | 8,531,870,409 | -0.48% | 304,608,346 |
|
||||
| 18 | Cardano | ada | 0.1900 | 7,138,766,905 | -0.16% | 235,438,100 |
|
||||
| 19 | Stellar | xlm | 0.1631 | 5,761,475,891 | -1.36% | 135,925,538 |
|
||||
| 20 | Bitcoin Cash | bch | 274.0400 | 5,511,420,220 | -0.88% | 146,355,359 |
|
||||
|
||||
*Full raw values in `crypto-top20-fresh.json`; machine-readable table in `2026-11-04-cryptos-top20.csv`.*
|
||||
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CHECK -- ledger: fresh CoinGecko top-20 table extraction, 2026-11-04.
|
||||
|
||||
Recomputes the expected table from crypto-top20-fresh.json and compares it
|
||||
cell-by-cell against the committed 2026-11-04-cryptos-top20.csv and the
|
||||
2026-11-04-cryptos-top20.md.
|
||||
|
||||
Exit code = verdict (0 pass, 1 fault, 2 ungradable):
|
||||
0 committed CSV + MD match the JSON source.
|
||||
1 mismatch.
|
||||
2 source unreadable / malformed.
|
||||
"""
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
SRC = os.path.join(HERE, "crypto-top20-fresh.json")
|
||||
CSV_PATH = os.path.join(HERE, "2026-11-04-cryptos-top20.csv")
|
||||
MD_PATH = os.path.join(HERE, "2026-11-04-cryptos-top20.md")
|
||||
|
||||
FAILS = []
|
||||
|
||||
|
||||
def fail(msg):
|
||||
FAILS.append(msg)
|
||||
|
||||
|
||||
def close(a, b, eps=1e-6):
|
||||
return abs(float(a) - float(b)) <= eps
|
||||
|
||||
|
||||
def main():
|
||||
# --- load source ---
|
||||
try:
|
||||
with open(SRC, encoding="utf-8") as f:
|
||||
source = json.load(f)
|
||||
except Exception as exc:
|
||||
print("UNGRADABLE: cannot read source JSON: %r" % exc)
|
||||
return 2
|
||||
if not isinstance(source, list) or len(source) != 20:
|
||||
print("UNGRADABLE: source not a 20-row list")
|
||||
return 2
|
||||
|
||||
# --- load committed CSV ---
|
||||
try:
|
||||
with open(CSV_PATH, newline="", encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
csv_rows = list(reader)
|
||||
except Exception as exc:
|
||||
print("UNGRADABLE: cannot read CSV: %r" % exc)
|
||||
return 2
|
||||
|
||||
expected = []
|
||||
for r in source:
|
||||
expected.append({
|
||||
"rank": int(r["rank"]),
|
||||
"name": r["name"],
|
||||
"symbol": r["symbol"],
|
||||
"price": float(r["price_usd"]),
|
||||
"market_cap": int(r["market_cap_usd"]),
|
||||
"change": float(r["market_cap_change_24h_pct"]),
|
||||
"volume": int(r["volume_24h_usd"]),
|
||||
})
|
||||
|
||||
if len(csv_rows) != len(expected):
|
||||
print("FAIL: CSV row count %d != expected %d" % (len(csv_rows), len(expected)))
|
||||
return 1
|
||||
|
||||
for i, (a, exp) in enumerate(zip(csv_rows, expected)):
|
||||
got = {
|
||||
"rank": int(a["rank"]),
|
||||
"name": a["name"],
|
||||
"symbol": a["symbol"],
|
||||
"price": float(a["price_usd"]),
|
||||
"market_cap": int(a["market_cap_usd"]),
|
||||
"change": float(a["market_cap_change_24h_pct"]),
|
||||
"volume": int(a["volume_24h_usd"]),
|
||||
}
|
||||
for col in expected[i]:
|
||||
if col == "name" or col == "symbol":
|
||||
if got[col] != exp[col]:
|
||||
fail("row %d %s: %r != %r" % (i, col, got[col], exp[col]))
|
||||
elif col == "rank":
|
||||
if got[col] != exp[col]:
|
||||
fail("row %d rank: %r != %r" % (i, got[col], exp[col]))
|
||||
else:
|
||||
if not close(got[col], exp[col]):
|
||||
fail("row %d %s: %r != %r" % (i, col, got[col], exp[col]))
|
||||
|
||||
if FAILS:
|
||||
print("FAIL (%d cell mismatch(es)):" % len(FAILS))
|
||||
for f in FAILS:
|
||||
print(" -", f)
|
||||
return 1
|
||||
|
||||
# --- verify markdown body ---
|
||||
try:
|
||||
with open(MD_PATH, encoding="utf-8") as f:
|
||||
md_lines = [ln for ln in f.read().splitlines() if ln.strip()]
|
||||
except Exception as exc:
|
||||
print("FAIL: cannot read MD: %r" % exc)
|
||||
return 1
|
||||
|
||||
# Locate the separator row (|---|---|---|---|---|---|---|) then count the
|
||||
# 20 rows beneath it.
|
||||
sep_idx = None
|
||||
for i, ln in enumerate(md_lines):
|
||||
cells = [c.strip() for c in ln.strip().strip("|").split("|")]
|
||||
if cells and all(c.startswith("-") for c in cells):
|
||||
sep_idx = i
|
||||
break
|
||||
if sep_idx is None:
|
||||
print("FAIL: no markdown table separator row found")
|
||||
return 1
|
||||
body = [ln for ln in md_lines[sep_idx + 1:]
|
||||
if ln.strip().startswith("|") and ln.strip() != ""]
|
||||
if len(body) != 20:
|
||||
print("FAIL: MD data rows %d != 20" % len(body))
|
||||
return 1
|
||||
|
||||
print("PASS: %d rows cell-exact vs crypto-top20-fresh.json; md has 20 rows" % len(csv_rows))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user