feat(数据源): 141个数据源全部通过真实API验证,含完整MD文档模板
新增内容: - 数据源接入验证报告_141个.md:完整验证报告含真实响应数据 - 5个批次验证脚本(verify_batch1-5.py) - 合并验证结果(all_verified_results.json) 数据源覆盖: - CEX: 42个(Binance/OKX/Bybit/Kraken/Gate.io/KuCoin/HTX/Bitfinex/Crypto.com/MEXC) - DEX: 7个(DexScreener/Hyperliquid/Raydium/1inch) - 链上: 12个(Blockchain.info/Mempool.space/Blockchair/Etherscan) - DeFi: 15个(DeFiLlama 12端点/Aave/Lido/L2排名) - 衍生品: 9个(Deribit 7端点/CoinGecko衍生品) - 社交: 10个(Reddit 8子版块/Nitter RSS/恐惧贪婪) - 宏观: 28个(Yahoo Finance 22端点/世界银行 6端点) - 综合: 18个(CoinGecko 8端点/CoinPaprika 7端点/CoinGlass/The Graph) 全部141个数据源100%免费,139个无需API Key
这个提交包含在:
@@ -0,0 +1,316 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
数据源验证脚本 - 第一批修复版
|
||||
修复 Binance interval、OKX/Bybit 参数、Deribit DVOL 参数
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
|
||||
TIMEOUT = 15
|
||||
results = {}
|
||||
|
||||
def test(name, fn):
|
||||
try:
|
||||
start = time.time()
|
||||
data = fn()
|
||||
elapsed = round((time.time() - start) * 1000)
|
||||
results[name] = {"status": "✅ 通过", "latency_ms": elapsed, "sample": data}
|
||||
print(f"✅ {name} ({elapsed}ms): {json.dumps(data, ensure_ascii=False, default=str)[:120]}")
|
||||
except Exception as e:
|
||||
results[name] = {"status": "❌ 失败", "error": str(e)}
|
||||
print(f"❌ {name}: {e}")
|
||||
|
||||
# ─── 1. Binance 合约 K 线(修复 interval 格式)─────────────────────────────
|
||||
def test_binance_klines():
|
||||
# 合约 K 线 interval 用 "10m" 不支持,改用 "15m" 或 "5m"
|
||||
url = "https://fapi.binance.com/fapi/v1/klines"
|
||||
r = requests.get(url, params={"symbol": "BTCUSDT", "interval": "15m", "limit": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
k = data[-1]
|
||||
return {"close_time": k[6], "open": k[1], "high": k[2], "low": k[3], "close": k[4], "volume": k[5]}
|
||||
|
||||
test("Binance合约K线(15m)", test_binance_klines)
|
||||
|
||||
# ─── 2. Binance 现货 K 线 ─────────────────────────────────────────────────
|
||||
def test_binance_spot():
|
||||
url = "https://api.binance.com/api/v3/klines"
|
||||
r = requests.get(url, params={"symbol": "BTCUSDT", "interval": "1h", "limit": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
k = data[-1]
|
||||
return {"open": k[1], "high": k[2], "low": k[3], "close": k[4], "volume": k[5]}
|
||||
|
||||
test("Binance现货K线(1h)", test_binance_spot)
|
||||
|
||||
# ─── 3. Binance 资金费率 ───────────────────────────────────────────────────
|
||||
def test_binance_funding():
|
||||
url = "https://fapi.binance.com/fapi/v1/premiumIndex"
|
||||
r = requests.get(url, params={"symbol": "BTCUSDT"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
return {"symbol": d["symbol"], "markPrice": d["markPrice"], "lastFundingRate": d["lastFundingRate"], "nextFundingTime": d["nextFundingTime"]}
|
||||
|
||||
test("Binance资金费率", test_binance_funding)
|
||||
|
||||
# ─── 4. Binance 未平仓量 ───────────────────────────────────────────────────
|
||||
def test_binance_oi():
|
||||
url = "https://fapi.binance.com/fapi/v1/openInterest"
|
||||
r = requests.get(url, params={"symbol": "BTCUSDT"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
return {"symbol": d["symbol"], "openInterest": d["openInterest"], "time": d["time"]}
|
||||
|
||||
test("Binance未平仓量", test_binance_oi)
|
||||
|
||||
# ─── 5. Binance 24h 行情 ──────────────────────────────────────────────────
|
||||
def test_binance_ticker():
|
||||
url = "https://fapi.binance.com/fapi/v1/ticker/24hr"
|
||||
r = requests.get(url, params={"symbol": "BTCUSDT"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
return {"lastPrice": d["lastPrice"], "priceChangePercent": d["priceChangePercent"], "volume": d["volume"], "quoteVolume": d["quoteVolume"]}
|
||||
|
||||
test("Binance24h行情", test_binance_ticker)
|
||||
|
||||
# ─── 6. OKX K 线(修复参数)──────────────────────────────────────────────
|
||||
def test_okx_klines():
|
||||
url = "https://www.okx.com/api/v5/market/candles"
|
||||
r = requests.get(url, params={"instId": "BTC-USDT-SWAP", "bar": "1H", "limit": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
if d["code"] != "0":
|
||||
raise Exception(f"OKX error: {d['msg']}")
|
||||
candle = d["data"][0]
|
||||
return {"ts": candle[0], "open": candle[1], "high": candle[2], "low": candle[3], "close": candle[4], "vol": candle[5]}
|
||||
|
||||
test("OKX合约K线(1H)", test_okx_klines)
|
||||
|
||||
# ─── 7. OKX 资金费率 ───────────────────────────────────────────────────────
|
||||
def test_okx_funding():
|
||||
url = "https://www.okx.com/api/v5/public/funding-rate"
|
||||
r = requests.get(url, params={"instId": "BTC-USDT-SWAP"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["data"][0]
|
||||
return {"instId": d["instId"], "fundingRate": d["fundingRate"], "nextFundingTime": d["nextFundingTime"]}
|
||||
|
||||
test("OKX资金费率", test_okx_funding)
|
||||
|
||||
# ─── 8. OKX 未平仓量 ──────────────────────────────────────────────────────
|
||||
def test_okx_oi():
|
||||
url = "https://www.okx.com/api/v5/rubik/stat/contracts/open-interest-volume"
|
||||
r = requests.get(url, params={"ccy": "BTC", "period": "1H"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
return {"code": d["code"], "data_count": len(d.get("data", []))}
|
||||
|
||||
test("OKX未平仓量", test_okx_oi)
|
||||
|
||||
# ─── 9. Bybit K 线(修复参数)────────────────────────────────────────────
|
||||
def test_bybit_klines():
|
||||
url = "https://api.bybit.com/v5/market/kline"
|
||||
r = requests.get(url, params={"category": "linear", "symbol": "BTCUSDT", "interval": "60", "limit": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
if d["retCode"] != 0:
|
||||
raise Exception(f"Bybit error: {d['retMsg']}")
|
||||
candle = d["result"]["list"][0]
|
||||
return {"startTime": candle[0], "open": candle[1], "high": candle[2], "low": candle[3], "close": candle[4], "volume": candle[5]}
|
||||
|
||||
test("Bybit合约K线(1h)", test_bybit_klines)
|
||||
|
||||
# ─── 10. Bybit 资金费率 ────────────────────────────────────────────────────
|
||||
def test_bybit_funding():
|
||||
url = "https://api.bybit.com/v5/market/funding/history"
|
||||
r = requests.get(url, params={"category": "linear", "symbol": "BTCUSDT", "limit": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["result"]["list"][0]
|
||||
return {"symbol": d["symbol"], "fundingRate": d["fundingRate"], "fundingRateTimestamp": d["fundingRateTimestamp"]}
|
||||
|
||||
test("Bybit资金费率", test_bybit_funding)
|
||||
|
||||
# ─── 11. Deribit 指数价格 ─────────────────────────────────────────────────
|
||||
def test_deribit_index():
|
||||
url = "https://www.deribit.com/api/v2/public/get_index_price"
|
||||
r = requests.get(url, params={"index_name": "btc_usd"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["result"]
|
||||
return {"index_price": d["index_price"]}
|
||||
|
||||
test("Deribit BTC指数价格", test_deribit_index)
|
||||
|
||||
# ─── 12. Deribit 期权合约列表 ─────────────────────────────────────────────
|
||||
def test_deribit_instruments():
|
||||
url = "https://www.deribit.com/api/v2/public/get_instruments"
|
||||
r = requests.get(url, params={"currency": "BTC", "kind": "option", "expired": "false"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["result"]
|
||||
# 只取最近到期的 3 个
|
||||
sample = [{"instrument_name": x["instrument_name"], "strike": x["strike"], "option_type": x["option_type"]} for x in d[:3]]
|
||||
return {"total_options": len(d), "sample": sample}
|
||||
|
||||
test("Deribit期权合约列表", test_deribit_instruments)
|
||||
|
||||
# ─── 13. Deribit DVOL(修复参数)─────────────────────────────────────────
|
||||
def test_deribit_dvol():
|
||||
import time as t
|
||||
end_ts = int(t.time() * 1000)
|
||||
start_ts = end_ts - 3600 * 1000 * 24 # 过去 24 小时
|
||||
url = "https://www.deribit.com/api/v2/public/get_volatility_index_data"
|
||||
r = requests.get(url, params={"currency": "BTC", "resolution": "3600", "start_timestamp": start_ts, "end_timestamp": end_ts}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["result"]["data"]
|
||||
if not d:
|
||||
raise Exception("No DVOL data returned")
|
||||
latest = d[-1]
|
||||
return {"timestamp": latest[0], "dvol": latest[1], "data_points": len(d)}
|
||||
|
||||
test("Deribit DVOL波动率指数", test_deribit_dvol)
|
||||
|
||||
# ─── 14. DeFiLlama 全链 TVL ───────────────────────────────────────────────
|
||||
def test_defillama_tvl():
|
||||
url = "https://api.llama.fi/charts"
|
||||
r = requests.get(url, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
latest = d[-1]
|
||||
return {"date": latest["date"], "totalLiquidityUSD": f"${latest['totalLiquidityUSD']/1e9:.2f}B", "data_points": len(d)}
|
||||
|
||||
test("DeFiLlama全链TVL", test_defillama_tvl)
|
||||
|
||||
# ─── 15. DeFiLlama 各链 TVL ───────────────────────────────────────────────
|
||||
def test_defillama_chains():
|
||||
url = "https://api.llama.fi/v2/chains"
|
||||
r = requests.get(url, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
top3 = [{"name": x["name"], "tvl": f"${x['tvl']/1e9:.2f}B"} for x in sorted(d, key=lambda x: x.get("tvl", 0), reverse=True)[:3]]
|
||||
return {"total_chains": len(d), "top3": top3}
|
||||
|
||||
test("DeFiLlama各链TVL", test_defillama_chains)
|
||||
|
||||
# ─── 16. DeFiLlama 稳定币数据 ─────────────────────────────────────────────
|
||||
def test_defillama_stablecoins():
|
||||
url = "https://stablecoins.llama.fi/stablecoins"
|
||||
r = requests.get(url, params={"includePrices": "true"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["peggedAssets"]
|
||||
top3 = [{"name": x["name"], "symbol": x["symbol"], "circulating": f"${x['circulating']['peggedUSD']/1e9:.2f}B"} for x in d[:3]]
|
||||
return {"total": len(d), "top3": top3}
|
||||
|
||||
test("DeFiLlama稳定币数据", test_defillama_stablecoins)
|
||||
|
||||
# ─── 17. Alternative.me 恐惧贪婪指数 ──────────────────────────────────────
|
||||
def test_fear_greed():
|
||||
url = "https://api.alternative.me/fng/?limit=3&format=json"
|
||||
r = requests.get(url, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["data"]
|
||||
return [{"value": x["value"], "classification": x["value_classification"], "timestamp": x["timestamp"]} for x in d]
|
||||
|
||||
test("Alternative.me恐惧贪婪指数", test_fear_greed)
|
||||
|
||||
# ─── 18. CoinGecko 全球数据 ───────────────────────────────────────────────
|
||||
def test_coingecko_global():
|
||||
url = "https://api.coingecko.com/api/v3/global"
|
||||
r = requests.get(url, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["data"]
|
||||
return {
|
||||
"total_market_cap_usd": f"${d['total_market_cap']['usd']/1e12:.2f}T",
|
||||
"btc_dominance": f"{d['market_cap_percentage']['btc']:.1f}%",
|
||||
"eth_dominance": f"{d['market_cap_percentage']['eth']:.1f}%",
|
||||
"market_cap_change_24h": f"{d['market_cap_change_percentage_24h_usd']:.2f}%"
|
||||
}
|
||||
|
||||
test("CoinGecko全球市场数据", test_coingecko_global)
|
||||
|
||||
# ─── 19. CoinGecko 币种价格 ───────────────────────────────────────────────
|
||||
def test_coingecko_price():
|
||||
url = "https://api.coingecko.com/api/v3/simple/price"
|
||||
r = requests.get(url, params={"ids": "bitcoin,ethereum,solana,binancecoin,dogecoin", "vs_currencies": "usd", "include_24hr_change": "true"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
return {k: {"usd": v["usd"], "24h_change": f"{v.get('usd_24h_change', 0):.2f}%"} for k, v in d.items()}
|
||||
|
||||
test("CoinGecko多币种价格", test_coingecko_price)
|
||||
|
||||
# ─── 20. Yahoo Finance 黄金价格 ───────────────────────────────────────────
|
||||
def test_yahoo_gold():
|
||||
url = "https://query1.finance.yahoo.com/v8/finance/chart/GC=F"
|
||||
r = requests.get(url, params={"interval": "1d", "range": "5d"}, headers={"User-Agent": "Mozilla/5.0"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["chart"]["result"][0]
|
||||
meta = d["meta"]
|
||||
return {"symbol": meta["symbol"], "regularMarketPrice": meta["regularMarketPrice"], "currency": meta["currency"]}
|
||||
|
||||
test("Yahoo Finance黄金(GC=F)", test_yahoo_gold)
|
||||
|
||||
# ─── 21. Yahoo Finance 美元指数 ───────────────────────────────────────────
|
||||
def test_yahoo_dxy():
|
||||
url = "https://query1.finance.yahoo.com/v8/finance/chart/DX-Y.NYB"
|
||||
r = requests.get(url, params={"interval": "1d", "range": "5d"}, headers={"User-Agent": "Mozilla/5.0"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["chart"]["result"][0]
|
||||
meta = d["meta"]
|
||||
return {"symbol": meta["symbol"], "regularMarketPrice": meta["regularMarketPrice"]}
|
||||
|
||||
test("Yahoo Finance美元指数(DXY)", test_yahoo_dxy)
|
||||
|
||||
# ─── 22. Yahoo Finance 标普500 ────────────────────────────────────────────
|
||||
def test_yahoo_sp500():
|
||||
url = "https://query1.finance.yahoo.com/v8/finance/chart/%5EGSPC"
|
||||
r = requests.get(url, params={"interval": "1d", "range": "5d"}, headers={"User-Agent": "Mozilla/5.0"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["chart"]["result"][0]
|
||||
meta = d["meta"]
|
||||
return {"symbol": meta["symbol"], "regularMarketPrice": meta["regularMarketPrice"]}
|
||||
|
||||
test("Yahoo Finance标普500(SPX)", test_yahoo_sp500)
|
||||
|
||||
# ─── 23. Yahoo Finance BTC ETF (IBIT) ────────────────────────────────────
|
||||
def test_yahoo_ibit():
|
||||
url = "https://query1.finance.yahoo.com/v8/finance/chart/IBIT"
|
||||
r = requests.get(url, params={"interval": "1d", "range": "5d"}, headers={"User-Agent": "Mozilla/5.0"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()["chart"]["result"][0]
|
||||
meta = d["meta"]
|
||||
return {"symbol": meta["symbol"], "regularMarketPrice": meta["regularMarketPrice"], "currency": meta["currency"]}
|
||||
|
||||
test("Yahoo Finance BTC ETF(IBIT)", test_yahoo_ibit)
|
||||
|
||||
# ─── 24. 世界银行 GDP 数据 ────────────────────────────────────────────────
|
||||
def test_worldbank():
|
||||
url = "https://api.worldbank.org/v2/country/US/indicator/NY.GDP.MKTP.CD"
|
||||
r = requests.get(url, params={"format": "json", "per_page": "3", "mrv": "3"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()[1]
|
||||
return [{"year": x["date"], "gdp_usd": f"${x['value']/1e12:.2f}T" if x["value"] else "N/A"} for x in d]
|
||||
|
||||
test("世界银行美国GDP", test_worldbank)
|
||||
|
||||
# ─── 25. The Graph Uniswap V3 ─────────────────────────────────────────────
|
||||
def test_thegraph():
|
||||
url = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v3"
|
||||
query = '{"query": "{ factories(first: 1) { poolCount txCount totalVolumeUSD } }"}'
|
||||
r = requests.post(url, data=query, headers={"Content-Type": "application/json"}, timeout=TIMEOUT)
|
||||
r.raise_for_status()
|
||||
d = r.json()
|
||||
if "errors" in d:
|
||||
raise Exception(str(d["errors"]))
|
||||
f = d["data"]["factories"][0]
|
||||
return {"poolCount": f["poolCount"], "txCount": f["txCount"], "totalVolumeUSD": f"${float(f['totalVolumeUSD'])/1e9:.0f}B"}
|
||||
|
||||
test("The Graph Uniswap V3", test_thegraph)
|
||||
|
||||
# ─── 保存结果 ──────────────────────────────────────────────────────────────
|
||||
print("\n=== 验证结果汇总 ===")
|
||||
passed = sum(1 for v in results.values() if "✅" in v["status"])
|
||||
failed = sum(1 for v in results.values() if "❌" in v["status"])
|
||||
print(f"通过: {passed}/{len(results)}, 失败: {failed}/{len(results)}")
|
||||
|
||||
with open("/home/ubuntu/quantKnowledge/20_Go迭代系统/scripts/verify_batch1_results.json", "w") as f:
|
||||
json.dump(results, f, ensure_ascii=False, indent=2, default=str)
|
||||
print("结果已保存")
|
||||
在新工单中引用
屏蔽一个用户