是定义方程里面一个循环语句中对各个股票赋予权重的环节
def momentum_and_contrarian(all_stock, start_date, end_date, window,observation): #window=形成期,observation=观测期
"""
:param all_stock: 所有股票的数据集
:param start_date: 起始日期(包含排名期)
:param end_date: 结束日期
:param window: 排名期的月份数,默认为3周
:return: 返回动量策略和反转策略的收益率和资金曲线
"""
# 取出指数数据作为交易天数的参考标准, 此处为指数数据文件的本地路径,请自行修改
index_data = pd.read_csv('C:\\Users\\SHIMAN\\Desktop\\沪深300英文\\沪深300英文1.csv',encoding='gbk', parse_dates=True, index_col='Date')
index_data.sort_index(inplace=True)
index_data = index_data[start_date:end_date]
# 转换成周度数据
by_week = index_data[['Closing Price (CNY)']].resample('W').last()
by_week.reset_index(inplace=True)
momentum_portfolio_all = pd.DataFrame()
contrarian_portfolio_all = pd.DataFrame()
for i in range(window, len(by_week) - observation):
start_week = by_week['Date'].iloc[i - window] # 排名期第一个月
end_week = by_week['Date'].iloc[i] # 排名期最后一个月
# 取出在排名期内的数据
stock_temp = all_stock[(all_stock['Date'] > start_week) & (all_stock['Date'] <= end_week)]
# 将指数在这段时间的数据取出作为交易日天数的标准
index_temp = index_data[start_week:end_week]
# 统计每只股票在排名期的交易日天数
trading_days = stock_temp['Symbol'].value_counts()
# 剔除在排名期内累计停牌超过(1*周数)天的股票,即如果排名期为3周,就剔除累计停牌超过3天的股票
keep_list = trading_days[trading_days >= (len(index_temp) - 1 * window)].index
stock_temp = stock_temp[stock_temp['Symbol'].isin(keep_list)]
stock_temp['% Chg']=pd.to_numeric(stock_temp['% Chg'], downcast='float',errors='coerce')
# 计算每只股票在排名期的累计收益率
grouped = stock_temp.groupby('Symbol')['% Chg'].agg([('return', lambda x: (x + 100).prod() - 1)])
# 将累计收益率排序
grouped.sort_values(by='return', inplace=True)
# 取排序后前5%的股票构造反转策略的组合,后5%的股票构造动量策略的组合
num = floor(len(grouped) * 0.05)
momentum_Symbol_list = grouped.index[-num:] # 动量组合的股票代码列表
contrarian_Symbol_list = grouped.index[0:num] # 反转组合的股票代码列表
# ============================动量组合============================
# 取出动量组合内股票当月的数据
momentum = all_stock.loc[(all_stock['Symbol'].isin(momentum_Symbol_list)) &
(all_stock['Date'] > end_week) & (all_stock['Date'] <= by_week['Date'].iloc[i + observation])]
# 剔除动量组合里在当月第一个交易日涨停的股票
temp = momentum.groupby('Symbol')['limit_up'].first()
hold_list = temp[temp == 0].index
momentum = momentum[momentum['Symbol'].isin(hold_list)].reset_index(drop=True)
# 动量组合
momentum_portfolio = momentum.pivot('Date', 'Symbol', '% Chg').fillna(0)
# 计算动量组合的收益率
num = momentum_portfolio.shape[1]
weights = num * [1. /num]
weights = [float(x) for x in weights]
momentum_portfolio=momentum_portfolio.astype(float)
momentum_portfolio['pf_rtn'] = np.dot(np.array(momentum_portfolio), np.array(weights))
momentum_portfolio.reset_index(inplace=True)
# 将每个月的动量组合收益数据合并
momentum_portfolio_all = momentum_portfolio_all.append(momentum_portfolio[['Date', 'pf_rtn']],
ignore_index=True)
# 计算动量策略的资金曲线
momentum_portfolio_all['capital'] = ((100 + momentum_portfolio_all['pf_rtn'])/100).cumprod()
# ============================反转组合=============================
# 取出反转组合内股票当月的数据
contrarian = all_stock.loc[(all_stock['Symbol'].isin(contrarian_Symbol_list)) &
(all_stock['Date'] > end_week) & (all_stock['Date'] <= by_week['Date'].iloc[i + observation])]
# 剔除反转组合里在当月第一个交易日涨停的股票
temp = contrarian.groupby('Symbol')['limit_up'].first()
hold_list = temp[temp == 0].index
contrarian = contrarian[contrarian['Symbol'].isin(hold_list)].reset_index(drop=True)
# 反转组合
contrarian_portfolio = contrarian.pivot('Date', 'Symbol', '% Chg').fillna(0)
# 计算反转组合的收益率
num = contrarian_portfolio.shape[1]
weights = num * [1. / num]
weights = [float(x) for x in weights]
contrarian_portfolio=contrarian_portfolio.astype(float)
contrarian_portfolio['pf_rtn'] = np.dot(np.array(contrarian_portfolio), np.array(weights))
contrarian_portfolio.reset_index(inplace=True)
# 将每个月的反转组合收益合并
contrarian_portfolio_all = contrarian_portfolio_all.append(contrarian_portfolio[['Date', 'pf_rtn']],
ignore_index=True)
# 计算反转策略的资金曲线
contrarian_portfolio_all['capital'] = ((100 + contrarian_portfolio_all['pf_rtn'])/100).cumprod()
return momentum_portfolio_all, contrarian_portfolio_all
m, c = momentum_and_contrarian(all_stock, '2019-01-01', '2021-12-31', window=3, observation=1)
成功为个股赋值
建议先对数据框进行处理,用dropna()滤除缺失数据,保证num在循环中不出现零值。
如果先不处理的话,用上述数据框直接遍历计算的话,应用if条件判断过滤,但是这样会出现空列表,可能会对后续的计算有影响。
for num in [3,5,8,0,1,2]:
weights = num * [1. / num] if num!=0 else num*[0]
print(weights)
我发现从循环语句里面print出来的num如下图
ZeroDivisionError: float division by zero这个错误表示
除数num的值为0了
除数是不能为0啊
对num判断下,为0时让weights 赋值为空列表即可
if num!=0:
weights = num * [1. / num]
else:
weights = []
如有帮助,请点击我的回答下方的【采纳该答案】按钮帮忙采纳下,谢谢!