870 字
4 分钟
vectorbt学习_21低相关性标的集合
在做基础资产组合(策略组合)时,往往需要筛选出一部分相关性较低的资产,构造出地相关性资产集合,基于低相关性性资产集合计算最佳的组合权重。
实现思路步骤
01,设定相似度阈值x,作为判断是否相似的依据
02,计算标的相关性矩阵,从中选择出相关性小于特定阈值的组合,加入到集合set A中,
03,重复步骤02,依次将相关性较小的标的,加入到SetA中。需保证,新加的标的,在SetA中不存在,且,和SetA中已经存在标的的相似度不超过阈值x
最终得到的setA中,两两之间相似度均比较低。
todo:其他思路,聚类算法的中心点
函数<获取行情>获取行情>,计算低相关性集合
from tools.dbtools import *
# 计算相似度的行情区间start_date = datetime(2020, 1, 1, tzinfo=pytz.utc)end_date = datetime(2023, 1, 1, tzinfo=pytz.utc)start_date_str= start_date.strftime("%Y-%m-%d")end_date_str= end_date.strftime("%Y-%m-%d")
def low_correlation_set(symbols=[],max_nan_days = 100,min_price_var=5.0,similar_threshold = 0.5): # max_nan_days: 最大nan行情,不添加此筛选,会选出长期停牌标的 # min_price_var: 过滤掉低方差标的,不添加此筛选,会选出小波动标的(大多为债基etf) # similar_threshold: 相似度阈值,高于此取值认为相似的
choose_set = set() # 低相关度标的集合 # 标的行情 yfdata=MySQLData.download(symbols,start_dt=start_date_str,end_dt=end_date_str) # 自带工具类查询
ohlcv = yfdata.concat() price = ohlcv['Close'] # 收盘价
# 过滤掉停牌次数过多的标的 price_nan=price.isna().sum()>=max_nan_days for key,value in price_nan.items(): if value: price.drop(columns=key,inplace=True)
# 过滤掉波动过小的标的 price_var=price.var()<min_price_var for key,value in price_var.items(): if value: price.drop(columns=key,inplace=True)
# 相似度计算 returns = price.pct_change() return_corr=returns.corr() corr_stack=return_corr.stack() corr_stack=corr_stack.sort_values() #相关度排序
# 低相关度股票组合 for idx in range(0,corr_stack.size,2): # 相似度矩阵corr是对称矩阵,stack后存在一半的重复记录,0-1或2-3其实对应同一个标的,类似pair(a,b)和(b,a)的关系,只取偶数避免重复计算 pair_stock=corr_stack.index[idx] if corr_stack[idx]<similar_threshold: for stock in pair_stock: if stock in choose_set: continue; isBreak=False for base_stock in choose_set: if corr_stack[(base_stock,stock)]>similar_threshold: isBreak=True # 说明和已经选中的某标的相似度过高 break if not isBreak: # 和选中的标的均不相似 choose_set.add(stock) return choose_set分批次计算相似度,沪深300为例
为了避免一次计算300只股票的相互相似度,采用分批次方式。每次查询50个股票行情,计算相似度,保留相似度较低的集合。反复6次,之后将得到的集合,做二次的相似度筛选。这样得到的集合内各股票相似度都低于设置的阈值。
def choose_stock_hs300(): batch_size=50 choose_set=set() for i in range(0,6): batch_start=i*batch_size batch_end=batch_start+batch_size
# 本批次标的,只考虑股票 sql_str ="select t.stock_code_market as code_market from jq_index_stocks t where t.index_code_market = '000300.XSHG' limit {},{};".format(batch_start,batch_size)
df = pd.read_sql(sql_str, DButil.get_conn()); symbols = df['code_market'].values print("limit {} - {} symbols:{}".format(batch_start,batch_end,symbols.size))
choose_set=choose_set.union(low_correlation_set(symbols,min_price_var=10.0,similar_threshold=0.3)) print("limit {} - {} choose_stock:{}".format(batch_start,batch_end,len(choose_set))) return choose_set结果保存到文件
将计算结果保存到txt文件
# 低相关度集合:沪深300choose_set=choose_stock_hs300() # 二次筛选,各个批次之间可能有高相似度的second_choose_set=low_correlation_set(list(choose_set))print("choose_set:{} choose_stock_hs300:{}".format(len(choose_set),len(second_choose_set)))print(second_choose_set)save_set_file(second_choose_set,"output/20231116_low_correlation_stock_hs300.txt")随机选择和可视化
# 可视化筛选出标的,观察是否存在显著问题# todo筛选出的均为,存在净值剧烈变动(累计净值没变)的etf
# 验证是否真的不相似import randomrandom_symbols = random.sample(second_choose_set, k=5) # 随机选择5个标的print("random_symbols:",random_symbols)yfdata=MySQLData.download(random_symbols,start_dt=start_date_str,end_dt=end_date_str) # 自带工具类查询
# 获取收盘价ohlcv = yfdata.concat()price = ohlcv['Close']
# 行情(收盘价)可视化(price / price.iloc[0]).vbt.plot().show_svg()
# 相似度returns = price.pct_change()return_corr=returns.corr()# print(returns.mean())# print(returns.std())print(return_corr)部分信息可能已经过时