import numpy as np
import pandas as pd
from datetime import datetime, date, timedelta, timezone
import jqdatasdk as jq
jq.auth("18351925110","925110")
auth success
核心思路:每年的5月末对股票池进行分组
分组策略:首先按照市值(size) 分为Big,前50%;Small ,后50%
然后按照账面价值比(bp),这里进行一个简化处理,选取pb(市净率)的相反数
分为LOW(前30%)Medium(中间40%) High(后30%)
股票组合:2*3 为BL BM BH SL SM SH
get_grooup(breakpoint): 返回6个因子组合,用来计算因子,为一个list
def get_group(breakpoint): #breakpoint 每年进行分组的时间点 字符类型 如:“2019-05-31”
breakpoint = jq.get_trade_days(end_date=breakpoint,count=1)[0] #获取breakpoint之前最近的一个交易日,含breakpoint
universe = jq.get_index_stocks("000300.XSHG",date=breakpoint) #获取沪深300指数的成分股
###############################取数据####################################################################
my_query = jq.query(jq.valuation.code,jq.valuation.circulating_market_cap,jq.valuation.pb_ratio).filter(jq.valuation.code.in_(universe))
stocks_info = jq.get_fundamentals(my_query,date=breakpoint) #获取股票的市值、PB数据
##################################算市值#################################################################
ME50 = np.percentile(stocks_info["circulating_market_cap"],50) #计算市值中位数
S = stocks_info[stocks_info["circulating_market_cap"]<=ME50]["code"].tolist() #获取小市值股票代码列表
B = stocks_info[stocks_info["circulating_market_cap"]>ME50]["code"].tolist() #获取大市值股票代码列表
#########################################算账面市值比####################################################
stocks_info["bp"] = 1/stocks_info["pb_ratio"]
BP30 = np.percentile(stocks_info["bp"],30) #计算前30%位数
BP70 = np.percentile(stocks_info["bp"],70) #计算后30%位数
L = stocks_info[stocks_info["bp"]<BP30]["code"].tolist()
H = stocks_info[stocks_info["bp"]>BP70]["code"].tolist()
M = list(set(stocks_info["code"]).difference(set(L+H)))
################################################构建股票组合#############################################
SL = list(set(S).intersection(set(L)))
SM = list(set(S).intersection(set(M)))
SH = list(set(S).intersection(set(H)))
BL = list(set(B).intersection(set(L)))
BM = list(set(B).intersection(set(M)))
BH = list(set(B).intersection(set(H)))
portfolios = [SL,SM,SH,BL,BM,BH]
return portfolios
# SL = get_group("2018-05-31")[0]
# SL
get_lastDay(year) : year为数字,来代表年份,如2019;返回值为该年每个月最后一个交易日,是一个字符List
import calendar
'''只能查到2005之后的数据(含2005年)'''
def get_lastDay(year): #year:指定年份 这是数字 如:2019
#首先获取每个月份的最后一天
last_day = {}
for i in range(1,13):
last_day[i] = calendar.monthrange(year,i)[1]
#获取每月月末的交易日
last_year_day = []
for i in last_day:
last_year_day.append(str(year)+"-"+str(i)+"-"+str(last_day[i]))
result = []
for i in last_year_day:
a = jq.get_trade_days(end_date=i,count=1)[0]
result.append(a)
return result #这是一个时间序列 list
def get_tradeDay(year):
tradeDay_0 = get_lastDay(year-1) #获取第一年每月最后一个交易日
tradeDay_1 = get_lastDay(year) #获取第二年每月最后一个交易日
tradeDay = tradeDay_0[4:] + tradeDay_1[:4] #获取周期为一年的,交易日
return tradeDay
get_returnMonthly(x,year,j),x:指定组合;year:哪一年,j:哪一月 j的具体含义见some_month相关语句
#以下的构造思路:以一个月为出发点进行函数编写
def get_returnMonthly(x,year,j): #x:指定组合(SM、SL....) year:数字年份,如2018 j=[0,1,2,3,...,11]某一数字
##########################获取每年5.31到次年5.31的交易日期########################
tradeDay_0 = get_lastDay(year-1) #获取第一年每月最后一个交易日
tradeDay_1 = get_lastDay(year) #获取第二年每月最后一个交易日
tradeDay = tradeDay_0[4:] + tradeDay_1[:5] #获取周期为一年的,交易日
some_month = tradeDay[j]
##########################计算组合某个月的收益率##################################
return_list = []
for i in x:
p0 = jq.get_price(i,end_date=some_month-timedelta(30),count=1,fields=["close"])
p1 = jq.get_price(i,end_date=some_month,count=1,fields=["close"])
ret = p1["close"].iloc[0]/p0["close"].iloc[0] - 1
return_list.append((i,ret))
return_df = pd.DataFrame(return_list,columns=["code","ret"])
###############################计算组合某个月的市值####################################
my_query = jq.query(jq.valuation.code,jq.valuation.circulating_market_cap).filter(jq.valuation.code.in_(x))
market_value_df = pd.DataFrame()
market_value = jq.get_fundamentals(my_query,date=some_month)
market_value["market_value_ratio"] = market_value["circulating_market_cap"]/market_value["circulating_market_cap"].sum()
market_value_df = pd.concat([market_value_df,market_value])
######################################合并两个df,并计算加权收益率##############################
final_result = pd.merge(market_value_df,return_df,on="code").dropna()
final_result["wret"] = final_result["ret"] * final_result["market_value_ratio"]
monthly_ret = final_result["wret"].sum()
return monthly_ret
# get_returnMonthly(SL,2006,0)
#假设就以2018.5.31为例,来算这个周期(2017.5.31-2018.5.31)的因子---SMB HML
#首先是获得2018年股票分组
portfolios = get_group("2013-05-31") #portfolios = [SL,SM,SH,BL,BM,BH]
#获取每个分组12个月的收益率
ret_dict = {}
for i in portfolios:
ret_ls = []
for j in range(12):
a = get_returnMonthly(i,2013,j) #这里还有一个年份参数
ret_ls.append(a)
ret_dict[str(i)] = ret_ls
result = ret_dict.values() #6个list 每个list里有12个收益率!
ret_ll = list(result)
a = pd.DataFrame(ret_ll,index=["SL","SM","SH","BL","BM","BH"]).T
a["SMB"] = (a["SL"]+a["SM"]+a["SH"]-a["BL"]-a["BM"]-a["BH"])/3
a["HML"] = (a["SH"]+a["BH"]-a["SL"]-a["BL"])/2
a.to_excel(r"C:\Users\Administrator\Desktop\论文\因子数据\因子_2013.xlsx")
思路:(月末指数-月初指数)/月初指数 - 1
df = pd.DataFrame()
for i in get_tradeDay(2013):
df1 = jq.get_price("000300.XSHG",end_date=i,count=1,fields=["close"])
df = pd.concat([df,df1])
df["close2"] = df.shift(1)["close"]
df["ret"] = (df["close"]/df["close2"])-1
df = df[["ret"]].bfill()
df.to_excel(r"C:\Users\Administrator\Desktop\论文\因子数据\沪深300_2013.xlsx") #记得此处的参数也得改