LOADING
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文件

# 低相关度集合:沪深300
choose_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 random
random_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)
vectorbt学习_21低相关性标的集合
/posts/quant/edd5e455/
作者
思想的巨人
发布于
2023-11-11
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时