我第一次在生产环境做加密货币相关性分析时,遇到了这个报错:ValueError: array must not contain infs or NaNs。当时从三个交易所拉取了交易对数据,满心欢喜想跑个相关性热力图,结果直接Crash。后来我发现,很多新手在做加密货币相关性分析时,不是数据清洗没做好,就是选错了相关系数方法。今天我就用一篇实战教程,把这两个核心问题一次性讲清楚。
为什么加密货币需要相关性分析?
在加密货币市场,相关性分析是构建多元化投资组合、对冲策略和风险管理的基石。比如你持有BTC和ETH,想知道它们的相关性是否足够低来分散风险;或者在做统计套利时,需要找出高度正相关或负相关的交易对。Pearson系数衡量线性相关性,Spearman系数衡量单调相关性——在加密货币这种波动剧烈的市场,两者往往差异显著。
数据获取与预处理
首先我们需要获取加密货币历史数据,这里使用HolySheep API获取Binance的K线数据:
import requests
import pandas as pd
import numpy as np
from scipy import stats
HolySheep API配置 - 国内直连延迟<50ms
BASE_URL = "https://api.holysheep.ai/v1"
API_KEY = "YOUR_HOLYSHEEP_API_KEY"
def get_binance_klines(symbol, interval="1h", limit=500):
"""
获取Binance K线数据
API文档: https://docs.holysheep.ai
"""
endpoint = f"{BASE_URL}/market/klines"
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
response = requests.get(endpoint, params=params, headers=headers, timeout=10)
if response.status_code == 401:
raise Exception("认证失败,请检查API Key是否正确配置")
elif response.status_code == 429:
raise Exception("请求频率超限,请降低调用频率或升级套餐")
data = response.json()
# 转换为DataFrame
df = pd.DataFrame(data, columns=[
"open_time", "open", "high", "low", "close", "volume",
"close_time", "quote_volume", "trades", "taker_buy_base",
"taker_buy_quote", "ignore"
])
# 数据类型转换
numeric_cols = ["open", "high", "low", "close", "volume", "quote_volume"]
df[numeric_cols] = df[numeric_cols].astype(float)
# 处理缺失值和异常值
df = df.dropna(subset=numeric_cols)
# 过滤价格为0或负数的异常数据
df = df[df["close"] > 0]
df = df[df["volume"] > 0]
return df
获取BTC和ETH的小时级数据
btc_df = get_binance_klines("BTCUSDT", interval="1h", limit=500)
eth_df = get_binance_klines("ETHUSDT", interval="1h", limit=500)
print(f"BTC数据行数: {len(btc_df)}, 价格范围: {btc_df['close'].min():.2f} - {btc_df['close'].max():.2f}")
print(f"ETH数据行数: {len(eth_df)}, 价格范围: {eth_df['close'].min():.2f} - {eth_df['close'].max():.2f}")
Pearson vs Spearman系数:核心区别与代码实现
Pearson系数衡量两个变量之间的线性关系强度,取值范围[-1, 1]。Spearman系数衡量单调关系,对异常值更鲁棒。在加密货币市场,由于价格经常出现极端波动,Spearman系数往往更能反映真实的关联性。
def calculate_correlations(btc_prices, eth_prices):
"""
计算Pearson和Spearman相关系数
返回: {pearson_r, pearson_p, spearman_r, spearman_p}
"""
# 确保数据对齐
min_len = min(len(btc_prices), len(eth_prices))
btc_aligned = btc_prices[:min_len].values
eth_aligned = eth_prices[:min_len].values
# Pearson相关系数
pearson_r, pearson_p = stats.pearsonr(btc_aligned, eth_aligned)
# Spearman相关系数
spearman_r, spearman_p = stats.spearmanr(btc_aligned, eth_aligned)
return {
"pearson_r": round(pearson_r, 4),
"pearson_p": round(pearson_p, 6),
"spearman_r": round(spearman_r, 4),
"spearman_p": round(spearman_p, 6)
}
计算BTC-USDT和ETH-USDT的相关性
result = calculate_correlations(btc_df["close"], eth_df["close"])
print("=" * 50)
print("BTC-USDT vs ETH-USDT 相关性分析结果")
print("=" * 50)
print(f"Pearson系数: {result['pearson_r']:.4f} (p值: {result['pearson_p']:.6f})")
print(f"Spearman系数: {result['spearman_r']:.4f} (p值: {result['spearman_p']:.6f})")
print("=" * 50)
判断相关性强度
def interpret_correlation(r):
abs_r = abs(r)
if abs_r >= 0.8:
strength = "强相关"
elif abs_r >= 0.5:
strength = "中等相关"
elif abs_r >= 0.3:
strength = "弱相关"
else:
strength = "几乎无相关"
direction = "正" if r > 0 else "负"
return f"{direction}{strength}"
print(f"\n解读: BTC与ETH呈现{interpret_correlation(result['pearson_r'])}关系")
实战:多交易对相关性矩阵热力图
在实际策略中,我们通常需要分析多个交易对的相关性,生成热力图辅助决策:
import matplotlib.pyplot as plt
import seaborn as sns
def build_correlation_matrix(symbols, interval="4h", limit=300):
"""
构建多交易对相关性矩阵
symbols: ["BTCUSDT", "ETHUSDT", "BNBUSDT", "SOLUSDT", "ADAUSDT"]
"""
price_data = {}
for symbol in symbols:
try:
df = get_binance_klines(symbol, interval=interval, limit=limit)
price_data[symbol] = df["close"].values
print(f"✓ {symbol} 数据获取成功")
except Exception as e:
print(f"✗ {symbol} 获取失败: {e}")
# 创建价格DataFrame
prices_df = pd.DataFrame(price_data)
prices_df = prices_df.dropna()
# 计算Pearson相关性矩阵
pearson_corr = prices_df.corr(method='pearson')
# 计算Spearman相关性矩阵
spearman_corr = prices_df.corr(method='spearman')
return pearson_corr, spearman_corr, prices_df
分析5个主流币种的相关性
symbols = ["BTCUSDT", "ETHUSDT", "BNBUSDT", "SOLUSDT", "ADAUSDT"]
pearson_corr, spearman_corr, _ = build_correlation_matrix(symbols)
print("\nPearson相关性矩阵:")
print(pearson_corr.round(3))
print("\nSpearman相关性矩阵:")
print(spearman_corr.round(3))
绘制对比热力图
fig, axes = plt.subplots(1, 2, figsize=(16, 6))
sns.heatmap(pearson_corr, annot=True, cmap='RdYlGn', center=0,
vmin=-1, vmax=1, ax=axes[0], fmt='.3f')
axes[0].set_title('Pearson相关性矩阵', fontsize=14)
sns.heatmap(spearman_corr, annot=True, cmap='RdYlGn', center=0,
vmin=-1, vmax=1, ax=axes[1], fmt='.3f')
axes[1].set_title('Spearman相关性矩阵', fontsize=14)
plt.tight_layout()
plt.savefig('crypto_correlation_heatmap.png', dpi=150)
print("\n热力图已保存至 crypto_correlation_heatmap.png")
滚动窗口相关性分析:捕捉时变关系
加密货币市场的相关性并非静态的,在极端行情中相关性会急剧上升(如同2022年LUNA崩盘期间)。我建议使用滚动窗口来分析相关性的时变特征:
def rolling_correlation_analysis(btc_prices, eth_prices, window=24):
"""
滚动窗口相关性分析
window: 滚动窗口大小(小时数)
"""
results = {
'timestamp': [],
'pearson': [],
'spearman': []
}
btc_array = btc_prices.values
eth_array = eth_prices.values
for i in range(window, len(btc_array)):
btc_window = btc_array[i-window:i]
eth_window = eth_array[i-window:i]
if len(btc_window) == window and len(eth_window) == window:
pearson_r, _ = stats.pearsonr(btc_window, eth_window)
spearman_r, _ = stats.spearmanr(btc_window, eth_window)
results['timestamp'].append(i)
results['pearson'].append(pearson_r)
results['spearman'].append(spearman_r)
return pd.DataFrame(results)
执行滚动相关性分析
rolling_df = rolling_correlation_analysis(btc_df["close"], eth_df["close"], window=48)
print("滚动窗口相关性统计(窗口=48小时):")
print(f" Pearson均值: {rolling_df['pearson'].mean():.4f}")
print(f" Pearson标准差: {rolling_df['pearson'].std():.4f}")
print(f" Pearson范围: [{rolling_df['pearson'].min():.4f}, {rolling_df['pearson'].max():.4f}]")
print(f"\n Spearman均值: {rolling_df['spearman'].mean():.4f}")
print(f" Spearman标准差: {rolling_df['spearman'].std():.4f}")
print(f" Spearman范围: [{rolling_df['spearman'].min():.4f}, {rolling_df['spearman'].max():.4f}]")
绘制时序图
plt.figure(figsize=(14, 6))
plt.plot(rolling_df['timestamp'], rolling_df['pearson'], label='Pearson', alpha=0.8)
plt.plot(rolling_df['timestamp'], rolling_df['spearman'], label='Spearman', alpha=0.8)
plt.axhline(y=0, color='gray', linestyle='--', linewidth=1)
plt.fill_between(rolling_df['timestamp'], rolling_df['pearson'], alpha=0.3)
plt.xlabel('时间序列索引')
plt.ylabel('相关系数')
plt.title('BTC-USDT vs ETH-USDT 滚动相关性时序图')
plt.legend()
plt.grid(True, alpha=0.3)
plt.savefig('rolling_correlation.png', dpi=150)
print("\n时序图已保存至 rolling_correlation.png")
常见报错排查
错误1:ValueError: array must not contain infs or NaNs
报错原因:数据中存在缺失值、无穷大或异常值,通常发生在交易所API返回非标准数据时。
解决方案:
def clean_price_data(df):
"""
清洗价格数据,处理缺失值和异常值
"""
numeric_cols = ["open", "high", "low", "close", "volume"]
# 移除包含NaN的行
df = df.dropna(subset=numeric_cols)
# 移除无穷大值
for col in numeric_cols:
df = df[~df[col].isin([np.inf, -np.inf])]
# 移除价格为0或负数的行
df = df[df["close"] > 0]
df = df[df["volume"] >= 0]
# 移除明显异常的价格数据(可自定义阈值)
price_stats = df["close"].describe()
q1 = price_stats["25%"]
q3 = price_stats["75%"]
iqr = q3 - q1
lower_bound = q1 - 3 * iqr # 使用3倍IQR作为异常值边界
upper_bound = q3 + 3 * iqr
df = df[(df["close"] >= lower_bound) & (df["close"] <= upper_bound)]
return df.reset_index(drop=True)
应用清洗函数
btc_df = clean_price_data(btc_df)
eth_df = clean_price_data(eth_df)
print(f"清洗后BTC数据行数: {len(btc_df)}")
错误2:401 Unauthorized 或 Authentication Error
报错原因:API Key配置错误、Key过期或权限不足。
解决方案:
- 检查API Key是否正确粘贴,确认没有多余空格或换行符
- 确认Key具有对应接口的访问权限
- 使用立即注册获取有效的API Key
- HolySheep提供¥1=$1无损汇率,相比官方节省85%+,且支持微信/支付宝充值
# 推荐的认证方式
import os
def get_authenticated_client():
"""
获取已认证的API客户端
"""
api_key = os.environ.get("HOLYSHEEP_API_KEY") or "YOUR_HOLYSHEEP_API_KEY"
if not api_key or api_key == "YOUR_HOLYSHEEP_API_KEY":
raise ValueError("请设置有效的API Key: export HOLYSHEEP_API_KEY='your_key'")
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
session = requests.Session()
session.headers.update(headers)
return session
验证连接
client = get_authenticated_client()
test_response = client.get(f"{BASE_URL}/market/ping")
if test_response.status_code == 200:
print("✓ API连接验证成功")
else:
print(f"✗ 连接失败: {test_response.status_code} - {test_response.text}")
错误3:ConnectionError 或 Timeout
报错原因:网络连接问题、请求超时或服务器端限流。
解决方案:
def get_klines_with_retry(symbol, interval="1h", limit=500, max_retries=3):
"""
带重试机制的数据获取函数
HolySheep国内直连延迟<50ms,可适当降低timeout
"""
import time
for attempt in range(max_retries):
try:
endpoint = f"{BASE_URL}/market/klines"
params = {"symbol": symbol, "interval": interval, "limit": limit}
response = requests.get(
endpoint,
params=params,
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=15 # 设置合理的超时时间
)
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
print(f"⏰ 第{attempt+1}次尝试超时,等待3秒后重试...")
time.sleep(3)
except requests.exceptions.ConnectionError as e:
print(f"🔌 连接错误: {e},等待5秒后重试...")
time.sleep(5)
except requests.exceptions.HTTPError as e:
if response.status_code == 429:
print(f"⚠️ 请求频率超限,等待60秒...")
time.sleep(60)
else:
raise e
raise Exception(f"数据获取失败,已重试{max_retries}次")
使用重试机制获取数据
btc_data = get_klines_with_retry("BTCUSDT")
print(f"✓ 成功获取BTC数据,共{len(btc_data)}条记录")
错误4:数据对齐不一致导致的相关性失真
报错原因:不同交易对的数据长度不同或时间戳不对齐。
解决方案:
def align_time_series_data(*dfs, time_col="open_time"):
"""
按时间戳对齐多个时间序列数据
"""
# 提取价格数据并设置时间为索引
aligned_dfs = []
for i, df in enumerate(dfs):
temp_df = df[[time_col, "close"]].copy()
temp_df[time_col] = pd.to_datetime(temp_df[time_col], unit='ms')
temp_df = temp_df.set_index(time_col)
temp_df.columns = [f"series_{i}"]
aligned_dfs.append(temp_df)
# 合并并内连接(只保留共同时间点)
aligned_df = pd.concat(aligned_dfs, axis=1)
aligned_df = aligned_df.dropna()
# 移除重复索引
aligned_df = aligned_df[~aligned_df.index.duplicated(keep='first')]
return aligned_df
对齐BTC和ETH数据
aligned_data = align_time_series_data(btc_df, eth_df)
print(f"对齐后数据点数: {len(aligned_data)}")
print(f"时间范围: {aligned_data.index.min()} 至 {aligned_data.index.max()}")
价格与性能对比
在获取加密货币数据时,HolySheep API提供极具竞争力的价格和性能:
| 服务商 | 基础延迟 | 汇率 | 充值方式 | 免费额度 |
|---|---|---|---|---|
| HolySheep | <50ms(国内直连) | ¥1=$1(无损) | 微信/支付宝/银行卡 | 注册即送 |
| 官方Binance API | 100-300ms | 官方汇率 | 仅支持国际支付 | 有限 |
| 其他中转服务 | 200-500ms | 溢价5-15% | 部分支持 | 较少 |
为什么选 HolySheep
- 极致低延迟:国内直连<50ms,远低于官方API的100-300ms,对于需要实时计算相关性的高频策略至关重要
- 汇率优势:¥1=$1无损汇率,相比官方节省85%+,支持微信/支付宝充值
- 数据完整性:支持Binance、Bybit、OKX等主流交易所,提供K线、Order Book、资金费率等全维度数据
- 高可用性:99.9%可用性SLA,智能负载均衡,自动故障转移
- 友好开发:Python/Node.js/Java多语言SDK,详尽文档和示例代码
结论与建议
对于加密货币相关性分析,我的实战经验是:
- 优先使用Spearman系数:加密货币价格分布往往偏离正态分布,Spearman对异常值更鲁棒
- 结合滚动窗口分析:静态相关性会掩盖市场结构变化,建议使用24-168小时的滚动窗口
- 做好数据清洗:交易所数据常包含异常值和缺失值,严格的数据预处理是准确分析的前提
- 关注相关性背离:当Pearson与Spearman差异过大时,往往暗示着市场结构变化或套利机会
如果你正在构建加密货币量化策略,需要稳定、快速的数据源,建议直接使用HolySheep API。国内直连低延迟、无损汇率、支持微信支付宝充值,这些特性对于国内开发者来说非常友好。