
昨天有个同学问我,怎么分析2只股票的相关度。 我心里想, 他该不是看了某些公众号 来问我的吧,我前几天貌似刷到过这样的文章。
其实我在看到那篇文章前, 之前就有所了解。 只是个人感觉对我没多大用,哪些概念个股比较相关,我自己脑海里基本有个七七八八。觉得没啥必要。 比如 中际旭创和新易盛, 中科曙光和浪潮信息, 贵州茅台和五粮液 什么的。
这2天qmt、ptrade 测试版关停了,没法登录上去。那这2天写点什么呢,那要不就写一写这个。 希望对大家有所帮助。
首先,我们先了解下,怎么判断2只股票的相关度?
思路基本是 选择这2只股票的相同时间的涨跌幅,看他们的相关度。相关度怎么判定,知道的同学应该明白答案了。一般采用皮尔逊相关系数、斯皮尔曼相关系数。这里解释下
皮尔逊相关系数: 皮尔逊相关系数(Pearson correlation coefficient)是一种线性相关系数,用来反映两个变量线性相关程度的统计量。它的核心是衡量两个变量之间线性关系的强度和方向。
斯皮尔曼相关系数: 斯皮尔曼等级相关系数(Spearman's rank correlation coefficient)经常用希腊字母ρ表示,是衡量两个变量的依赖性的 非参数 指标。它利用单调方程评价两个统计变量的相关性,不要求数据是连续的,也不要求数据呈正态分布。
如何选择这两种系数?
选择使用皮尔逊相关系数还是斯皮尔曼相关系数,主要取决于你的数据特征和分析目的。
用AI辅助写了一个例子,你可以试一试。 如果大A全市场,那就最好把所有数据集用自己本地的数据集, 多线性循环实现。
这里贴一下完整代码,参考下思路, 具体根据自己的实际情况改造。 备注:如果发现格式有多余的特殊字符,用普通浏览器打开复制应该没问题。 希望我的分享对大家有所帮助
# -*- coding: utf-8 -*-
"""
使用AkShare计算两只股票收益率相关性的完整代码
"""
import akshare as ak
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timedelta
# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.style.use('seaborn-v0_8') # 设置图形风格
def get_stock_data(symbol, start_date, end_date):
"""
获取单只股票历史数据
Parameters:
symbol (str): 股票代码,如"000001"
start_date (str): 开始日期,格式"YYYYMMDD"
end_date (str): 结束日期,格式"YYYYMMDD"
Returns:
pandas.DataFrame: 股票历史数据
"""
try:
# 获取前复权数据
df = ak.stock_zh_a_hist(symbol=symbol, period="daily",
start_date=start_date, end_date=end_date,
adjust="qfq")
# 确保日期格式正确并设置为索引
df['日期'] = pd.to_datetime(df['日期'])
df.set_index('日期', inplace=True)
return df
except Exception as e:
print(f"获取股票 {symbol} 数据时出错: {e}")
return None
def calculate_correlation(returns_df, col1, col2, method='pearson'):
"""
计算两只股票收益率的相关系数
Parameters:
returns_df (pandas.DataFrame): 包含收益率的DataFrame
col1 (str): 第一只股票的列名
col2 (str): 第二只股票的列名
method (str): 相关系数计算方法,'pearson'或'spearman'
Returns:
float: 相关系数
"""
return returns_df[col1].corr(returns_df[col2], method=method)
def analyze_stock_correlation(symbol1, symbol2, start_date, end_date, window=30):
"""
分析两只股票的相关性
Parameters:
symbol1 (str): 第一只股票代码
symbol2 (str): 第二只股票代码
start_date (str): 开始日期
end_date (str): 结束日期
window (int): 滚动相关性窗口大小
Returns:
dict: 包含分析结果的字典
"""
# 获取数据
print("正在获取股票数据...")
stock1_data = get_stock_data(symbol1, start_date, end_date)
stock2_data = get_stock_data(symbol2, start_date, end_date)
if stock1_data is None or stock2_data is None:
print("数据获取失败,请检查股票代码和日期范围")
return None
# 合并两只股票的收盘价数据
combined_data = pd.DataFrame({
f'{symbol1}_close': stock1_data['收盘'],
f'{symbol2}_close': stock2_data['收盘']
})
# 处理缺失值
combined_data.dropna(inplace=True)
# 计算每日收益率(百分比变化)
returns = combined_data.pct_change().dropna()
returns.columns = [f'{symbol1}_return', f'{symbol2}_return']
# 计算相关系数
pearson_corr = calculate_correlation(returns, f'{symbol1}_return', f'{symbol2}_return', 'pearson')
spearman_corr = calculate_correlation(returns, f'{symbol1}_return', f'{symbol2}_return', 'spearman')
# 计算滚动相关性
rolling_corr = returns[f'{symbol1}_return'].rolling(window=window).corr(returns[f'{symbol2}_return'])
# 计算协方差
covariance = np.cov(returns[f'{symbol1}_return'], returns[f'{symbol2}_return'])[0, 1]
return {
'combined_data': combined_data,
'returns': returns,
'pearson_corr': pearson_corr,
'spearman_corr': spearman_corr,
'rolling_corr': rolling_corr,
'covariance': covariance
}
def plot_correlation_analysis(results, symbol1, symbol2):
"""
绘制相关性分析图表
Parameters:
results (dict): 分析结果字典
symbol1 (str): 第一只股票代码
symbol2 (str): 第二只股票代码
"""
# 准备数据
returns = results['returns']
rolling_corr = results['rolling_corr']
combined_data = results['combined_data']
# 创建图表
fig, axes = plt.subplots(2, 2, figsize=(15, 12))
fig.suptitle(f'{symbol1} 与 {symbol2} 相关性分析', fontsize=16)
# 1. 价格走势对比图(标准化)
ax1 = axes[0, 0]
normalized_prices = combined_data / combined_data.iloc[0]
ax1.plot(normalized_prices[f'{symbol1}_close'], label=f'股票{symbol1}')
ax1.plot(normalized_prices[f'{symbol2}_close'], label=f'股票{symbol2}')
ax1.set_title('标准化价格走势对比')
ax1.set_xlabel('日期')
ax1.set_ylabel('标准化价格')
ax1.legend()
ax1.grid(True)
# 2. 收益率散点图
ax2 = axes[0, 1]
ax2.scatter(returns[f'{symbol1}_return'], returns[f'{symbol2}_return'], alpha=0.5)
# 添加趋势线
z = np.polyfit(returns[f'{symbol1}_return'], returns[f'{symbol2}_return'], 1)
p = np.poly1d(z)
x_range = np.linspace(returns[f'{symbol1}_return'].min(), returns[f'{symbol1}_return'].max(), 100)
ax2.plot(x_range, p(x_range), "r--", alpha=0.8, label='趋势线')
ax2.set_xlabel(f'{symbol1}收益率')
ax2.set_ylabel(f'{symbol2}收益率')
ax2.set_title('每日收益率散点图')
ax2.legend()
ax2.grid(True)
# 3. 滚动相关系数图
ax3 = axes[1, 0]
ax3.plot(rolling_corr, label=f'{window}日滚动相关系数', color='purple')
ax3.axhline(y=results['pearson_corr'], color='r', linestyle='--', label='整体皮尔逊相关系数')
ax3.axhline(y=0, color='gray', linestyle='-', alpha=0.3)
ax3.set_xlabel('日期')
ax3.set_ylabel('相关系数')
ax3.set_title('滚动相关系数趋势')
ax3.legend()
ax3.grid(True)
# 4. 收益率分布直方图
ax4 = axes[1, 1]
ax4.hist(returns[f'{symbol1}_return'], bins=50, alpha=0.5, label=f'股票{symbol1}', density=True)
ax4.hist(returns[f'{symbol2}_return'], bins=50, alpha=0.5, label=f'股票{symbol2}', density=True)
ax4.set_xlabel('日收益率')
ax4.set_ylabel('密度')
ax4.set_title('收益率分布对比')
ax4.legend()
ax4.grid(True)
plt.tight_layout()
plt.show()
def print_correlation_summary(results, symbol1, symbol2):
"""
打印相关性分析摘要
Parameters:
results (dict): 分析结果字典
symbol1 (str): 第一只股票代码
symbol2 (str): 第二只股票代码
"""
print("=" * 60)
print(f"{symbol1} 与 {symbol2} 相关性分析结果")
print("=" * 60)
print(f"分析期间: {start_date} 至 {end_date}")
print(f"样本数量: {len(results['returns'])} 个交易日")
print(f"皮尔逊相关系数: {results['pearson_corr']:.4f}")
print(f"斯皮尔曼相关系数: {results['spearman_corr']:.4f}")
print(f"协方差: {results['covariance']:.6f}")
# 解释相关性强度
def interpret_correlation(corr_value):
abs_value = abs(corr_value)
if abs_value >= 0.7:
return "强相关"
elif abs_value >= 0.4:
return "中等相关"
elif abs_value >= 0.2:
return "弱相关"
else:
return "极弱相关或不相关"
print(f"\n相关性解释:")
print(f"皮尔逊相关系数表明两只股票存在{interpret_correlation(results['pearson_corr'])}关系")
print(f"斯皮尔曼相关系数表明两只股票存在{interpret_correlation(results['spearman_corr'])}关系")
# 滚动相关性的统计特征
rolling_corr = results['rolling_corr'].dropna()
if len(rolling_corr) > 0:
print(f"\n滚动相关性统计 ({window}日窗口):")
print(f" 均值: {rolling_corr.mean():.4f}")
print(f" 标准差: {rolling_corr.std():.4f}")
print(f" 最大值: {rolling_corr.max():.4f}")
print(f" 最小值: {rolling_corr.min():.4f}")
print(f" 最后值: {rolling_corr.iloc[-1]:.4f}")
print("=" * 60)
# 主程序
if __name__ == "__main__":
# 设置分析参数
symbol1 = "300308" # 中际旭创
symbol2 = "300502" # 新易盛
start_date = "20240101" # 开始日期
end_date = "20250901" # 结束日期
window = 30 # 滚动相关性窗口大小
# 执行相关性分析
results = analyze_stock_correlation(symbol1, symbol2, start_date, end_date, window)
if results is not None:
# 打印分析结果
print_correlation_summary(results, symbol1, symbol2)
# 绘制图表
plot_correlation_analysis(results, symbol1, symbol2)
# 保存结果到CSV文件
results['returns'].to_csv(f'stock_returns_{symbol1}_{symbol2}.csv')
results['rolling_corr'].to_csv(f'rolling_correlation_{symbol1}_{symbol2}.csv')
print("结果已保存到CSV文件")如果我的分享对你投资有所帮助,不吝啬给个点赞关注呗。