def period_return_maker_(chooseday_r, factor_value, indicator): date_r2 = month(chooseday_r, change_month=-12) date = chooseday_r if len(date) <= 8: date_r = date[0:4] + '-' + date[4:6] + '-' + date[6:8] else: date_r = date # 创建某时刻截面指标df df_values = pd.DataFrame(columns=['date', 'code', 'factor_value'], index=range(len(factor_value))) df_values['date'] = date df_values['code'] = factor_value['code'] df_values['factor_value'] = factor_value[indicator] # 指标选择 # 对指标进行标准化 df_values['factor_value'] = (df_values['factor_value'] - df_values['factor_value'].min()) \ / (df_values['factor_value'].max() - df_values['factor_value'].min()) # 标准化 # 创建该段时间所有股票的收益率pool returns = get_data_panel("huangwei", "huangwei", list(df_values['code']), date_r2, date_r, collection='stock_daily') df_price = pd.DataFrame(columns=['date', 'code'], index=range(len(df_values))) df_price['date'] = date df_price['code'] = df_values['code'] df_price['cum_return'] = 0 # 计算每只股票在这段时间的累计收益,并填入cum_return中 def caculate_cum_return(code): one_stock = returns[returns['code'] == code].reset_index(drop=True) unique_index = list(one_stock['date'].drop_duplicates( keep='first', inplace=False).index) one_stock = one_stock.iloc[unique_index].sort_values(by='date') one_stock['rtn'] += 1 one_stock['c_rtn'] = one_stock['rtn'].cumprod() return one_stock['c_rtn'].iloc[-1] - one_stock['c_rtn'].iloc[0] df_price['cum_return'] = df_price['code'].apply(caculate_cum_return) # 合并收盘价以及指标值数据,计算两者截面相关性 df_all = df_price.merge(df_values[['code', 'factor_value']], how='inner', on='code') # 剔除不匹配的股票 df_all = df_all.dropna(axis=0, how='any').reset_index(drop=True) ic, p = spearman_cor(df_all['cum_return'].values, df_all['factor_value'].values) print('IC值计算完毕') return ic, p
def _open_convert_database(self): all_data = get_data_panel("huangwei", "huangwei", self.symbol_list, '2017-03-01', '2019-08-01', collection='stock_daily') comb_index = None for s in self.symbol_list: one_stock = all_data[all_data['code'] == s][[ 'date', 'open', 'high', 'low', 'close', 'vol', 'rtn' ]] one_stock = one_stock.rename(columns={ "date": "datetime", "vol": "volume" }) one_stock['adj_close'] = 0 one_stock_arr = one_stock.values for i in range(len(one_stock_arr)): if i == 0: one_stock_arr[i, 7] = one_stock_arr[i, 4] \ * (1 + one_stock_arr[i, 6]) else: one_stock_arr[i, 7] = one_stock_arr[i - 1, 7] \ * (1 + one_stock_arr[i, 6]) one_stock = pd.DataFrame(one_stock_arr, columns=one_stock.columns, index=range(len(one_stock))) del one_stock['rtn'] # 将datatime作为index,并改为datatime格式 one_stock['datetime'] = pd.to_datetime(one_stock['datetime']) one_stock.set_index(["datetime"], inplace=True) one_stock = one_stock.fillna(method='ffill') # ffill:用前一个非缺失值去填充该缺失值(向后填充) # bfill:用下一个非缺失值填充该缺失值(向前填充) self.symbol_data[s] = one_stock.sort_values(by="datetime", ascending=True) # Combine the index to pad forward values if comb_index is None: comb_index = self.symbol_data[s].index else: comb_index.union(self.symbol_data[s].index) # 这里对于不同股票的日期会不断叠加,直到得到一列所有股票里面最长的 # Set the latest symbol_data to None self.latest_symbol_data[s] = [] # Reindex the dataframes for s in self.symbol_list: self.symbol_data[s] = self.symbol_data[s].reindex( index=comb_index, method='pad').iterrows()
def get_data_(cal_day, indicator): # 读取所有股票信息表 stock_info = pd.read_excel( 'C:/Users/Lenovo/PycharmProjects/my_project/frjj_codes/stock_info_20190801.xlsx' ) stock_info = stock_info.dropna(axis=0, how='any').reset_index(drop=True) # 与指数成分股取交集 index_content_now = index_content[index_content['date'] == list( index_content['date'][index_content['date'] >= cal_day]) [0]].reset_index(drop=True) index_content_now.rename(columns={'stock_code': '证券代码'}, inplace=True) stock_info = stock_info.merge(index_content_now['证券代码'], on='证券代码', how='inner') # 读取申万一级行业划分 sw1 = sw_info_(cal_day, "sw1") sw1.rename(columns={'sw_name': 'sw1_name'}, inplace=True) # 读取申万三级行业划分 sw3 = sw_info_(cal_day, "sw3") sw3.rename(columns={'sw_name': 'sw3_name'}, inplace=True) all = pd.DataFrame(columns=['code', 'code_name'], index=range(len(stock_info))) all['code'] = stock_info['证券代码'] all['code_name'] = stock_info['证券简称'] all = all.merge(sw1[['code', 'sw1_code', 'sw1_name']], on='code', how='left') all = all.merge(sw3[['code', 'sw3_code', 'sw3_name']], on='code', how='left') # 使cal_day适应api if len(cal_day) == 8: cal_day = cal_day[0:4] + '-' + cal_day[4:6] + '-' + cal_day[6:8] else: pass # 直接从数据库收集股票的流通市值(或总市值) data = get_data_panel("huangwei", "huangwei", list(all['code']), forwardchangeday2(cal_day), forwardchangeday2(cal_day), collection='stock_indicator') # 用total_mv替换原表的cir_mv all = all.merge(data[['code', indicator]], on='code', how='left') all['cir_mv'] = all[indicator] del all[indicator] return all
def weight_maker_(chooseday_r, weight_origin, how=0): user = "******" passwd = "huangwei" weight = weight_origin if how == 0: # 等权 weight['weight_adj_sw1'] = 1 / len(weight_origin) print('持仓赋权方式为:等权') elif how == 1: # 按市值加权,取出这天股票组合的市值信息 if 'total_mv' not in weight.columns: info_all = get_data_panel(user, passwd, list(weight['code']), chooseday_r, chooseday_r, collection='stock_indicator') weight = weight.merge(info_all[['code', 'total_mv']], how='inner', on='code') else: pass weight_sum = sum(weight['total_mv']) weight['weight_adj_sw1'] = weight['total_mv'] / weight_sum del weight['total_mv'] print('持仓赋权方式为:市值加权') elif how == 2: # 按过去一年收益率波动率倒数 # 获取当下日期过去一年的收益率数据 info_all = get_data_panel_backwards(user, passwd, list(weight['code']), chooseday_r, back_years=0, back_months=12, collection='stock_daily') info_all = info_all.rename(columns={'code': 'codes'}) # 分组统计标准差 grouped = info_all.groupby(by=info_all['codes']).std() grouped['code'] = grouped.index weight = weight.merge(grouped[['code', 'rtn']], how='inner', on='code') weight['rtn'] = 1 / weight['rtn'] weight['rtn'] = weight['rtn'].ffill() # 缺失值延续前值 weight['weight_sum'] = sum(weight['rtn']) weight['weight_adj_sw1'] = weight['rtn'] / weight['weight_sum'] print('持仓赋权方式为:波动率倒数加权') return weight
def get_data_(cal_day, indicator): # 与指数成分股取交集 index_content_now = index_content[index_content['date'] == list( index_content['date'][index_content['date'] >= cal_day]) [0]].reset_index(drop=True) index_content_now.rename(columns={'stock_code': '证券代码'}, inplace=True) stock_info_ = stock_info.merge(index_content_now['证券代码'], on='证券代码', how='inner') # 取当天的申万行业划分 sw_ = sw[sw['date'] == cal_day].reset_index(drop=True) all = pd.DataFrame(columns=['code', 'code_name'], index=range(len(stock_info_))) all['code'] = stock_info_['证券代码'] all['code_name'] = stock_info_['证券简称'] all = all.merge(sw_[[ 'code', 'sw1_code', 'sw1_name', 'sw2_code', 'sw2_name', 'sw3_code', 'sw3_name' ]], on='code', how='left') # 使cal_day适应api if len(cal_day) == 8: cal_day = cal_day[0:4] + '-' + cal_day[4:6] + '-' + cal_day[6:8] else: pass # 直接从数据库收集股票的流通市值(或总市值) data = get_data_panel("huangwei", "huangwei", list(all['code']), forwardchangeday2(cal_day), forwardchangeday2(cal_day), collection='stock_indicator') # 用total_mv替换原表的cir_mv all = all.merge(data[['code', indicator]], on='code', how='left') all['cir_mv'] = all[indicator] del all[indicator] return all
def position_init_(stock_pool, changeday, total_capitals): # 持仓矩阵初始化 position = pd.DataFrame(columns=['date', 'code', 'weight', 'account', 'open_price', 'lots', 'account_surplus', 'close_price'], index=range(len(stock_pool))) position['code'] = stock_pool['code'] position['weight'] = stock_pool['weight_adj_sw1'] position['date'] = changeday position['account'] = total_capitals[-1] * position['weight'] # 计算每个股票的应买手数 price = get_data_panel("huangwei", "huangwei", list(position['code']), changeday, changeday, collection='stock_daily').drop_duplicates(['code']) if 'open' in position.columns: del position['open'] if 'rtn' in position.columns: del position['rtn'] position = position.merge(price[['code', 'open', 'rtn']], on='code', how='inner') position['open_price'] = position['open'] position['close_price'] = position['open_price'] * (1 + position['rtn']) position['lots'] = position['account'] / (100 * position['open_price']) # 对于获取不到开盘价的股票,可买手数一律赋0 position['lots'] = position['lots'].fillna(0) # 为了方便计算剩余资金,创造facked字段,开盘价为nan的赋为0 position['open_price_faked'] = position['open_price'].fillna(0) position['lots'] = position['lots'].apply(lambda x: math.floor(x)) position['account_realized'] = 100 * position['open_price_faked'] * position['lots'] position['account_surplus'] = position['account'] - position['account_realized'] return position
'cir_mv_y': 'industry_total_sw1' }, inplace=True) # 申万一级行业的比重*行业内部个股占整个行业的比重 result['weight_adj_sw1'] = result['industryweight_in_all'] * result[ 'weight_in_industry_sw1'] result['weight_adj_sw1'] = result['weight_adj_sw1'] / result[ 'weight_adj_sw1'].sum() # 计算股票池的净值曲线 # 获得每只股票在回测期的日收益率(除权调整),累积日收益率数据 begin_date = '20160104' end_date = "20190628" data = get_data_panel("huangwei", "huangwei", list(result_top100mv['code']), begin_date, end_date) data_unlimited = get_data_panel("huangwei", "huangwei", list(result['code']), begin_date, end_date) dates = get_tradingdays("huangwei", "huangwei", begin_date, end_date) dates = dates.rename(columns={'tradingdays': 'date'}) for i in range(len(dates)): dates['date'].iloc[i] = dates['date'].iloc[i][0:4] + '-' + \ dates['date'].iloc[i][4:6] + '-' + dates['date'].iloc[i][6:8] df_group_data_limited = dates df_group_data_unlimited = dates # 限定在沪深300成分股内 for code in list(result_top100mv['code']): temp = data[data['code'] == code].reset_index(drop=True) unique_index = list(temp['date'].drop_duplicates(keep='first',
if result_export: # 输出持仓信息 export_result_(position, changeday, result_path, file_name1) # 记录当天的损益 pnls, total_capitals = return_maker_(position, pnls, total_capitals, transaction_cost_rate) # last_stock_pool = stock_pool_class elif changeday != change_days[0] and changeday in change_days: # 调仓日 # 更新开盘价数据 price = get_data_panel("huangwei", "huangwei", list(position['code']), changeday, changeday, collection='stock_daily').drop_duplicates( ['code']) # 保存过去的持仓情况 last_position = position if 'open' in last_position.columns: del last_position['open'] if 'rtn' in last_position.columns: del last_position['rtn'] last_position = last_position.merge(price[['code', 'open', 'rtn']], on='code', how='inner') last_position['open_price'] = last_position['open'] last_position['close_price'] = last_position['open_price'] \ * (1 + last_position['rtn'])
def industry_leader_maker_(cal_day, indicator, industry_weight, top_num, index_for_simple_weight): """ :param stock_info: 当下A股市场的所有股票名称、代码信息 :param cal_day: 选股日期 :param indicator: 选股时引入的财务指标,包括总市值(total_mv)、流通市值(circ_mv) :param industry_weight: 根据某指数,复制其行业权重。或者'market':按全市场行业权重 :param top_num: 是否选择前几只 :param index_for_simple_weight:对于按某指数成分简单赋权 :return: """ # 读取股票信息表 stock_info = pd.read_excel( 'C:/Users/Lenovo/PycharmProjects/my_project/frjj_codes/stock_info_20190801.xlsx' ) stock_info = stock_info.dropna(axis=0, how='any').reset_index(drop=True) # 读取申万一级行业划分 sw1 = sw_info_(cal_day, "sw1") sw1.rename(columns={'sw_name': 'sw1_name'}, inplace=True) # 读取申万三级行业划分 sw3 = sw_info_(cal_day, "sw3") sw3.rename(columns={'sw_name': 'sw3_name'}, inplace=True) all = pd.DataFrame(columns=['code', 'code_name'], index=range(len(stock_info))) all['code'] = stock_info['证券代码'] all['code_name'] = stock_info['证券简称'] all = all.merge(sw1[['code', 'sw1_code', 'sw1_name']], on='code', how='left') all = all.merge(sw3[['code', 'sw3_code', 'sw3_name']], on='code', how='left') # 使cal_day适应api cal_day = cal_day[0:4] + '-' + cal_day[4:6] + '-' + cal_day[6:8] # 直接从数据库收集股票的流通市值(或总市值) data = get_data_panel("huangwei", "huangwei", list(all['code']), forwardchangeday2(cal_day), forwardchangeday2(cal_day), collection='stock_indicator') # 替换原表的cir_mv all = all.merge(data[['code', indicator]], on='code', how='left') all['cir_mv'] = all[indicator] del all[indicator] # 计算申万三级行业内部流通市值比例 tot_industry = all.groupby('sw3_code').sum() tot_industry['sw3_code'] = tot_industry.index tot_industry = tot_industry.reset_index(drop=True) all = all.merge(tot_industry, on='sw3_code', how='inner') all['weight_in_industry'] = all['cir_mv_x'] / all['cir_mv_y'] all.rename(columns={ 'cir_mv_x': 'cir_mv', 'cir_mv_y': 'industry_total' }, inplace=True) if industry_weight == 'market': # 获得全市场每个申万一级行业的比重 tot_industry_sw1 = all.groupby('sw1_code').sum() tot_industry_sw1['sw1_code'] = tot_industry_sw1.index total_mv = tot_industry_sw1['cir_mv'].sum() tot_industry_sw1[ 'industryweight_in_all'] = tot_industry_sw1['cir_mv'] / total_mv tot_industry_sw1.index.name = 'sw1_codes' # 更改level_name all = all.merge(tot_industry_sw1[['industryweight_in_all', 'sw1_code']], on='sw1_code', how='inner') else: # 获得成分股中每个申万一级行业的比重 zz500_weight = get_data_crosssection_genaral("huangwei", "huangwei", "index_weight", 'index_code', industry_weight) zz500_weight = zz500_weight[zz500_weight['date'] == list( zz500_weight['date'][zz500_weight['date'] >= cal_day]) [0]].reset_index(drop=True) # 与成分股权重表匹配最接近的日期 zz500_weight.rename(columns={'stock_code': 'code'}, inplace=True) # 获取中证500中成分股的申万一级行业信息及流通市值信息 zz500_weight = zz500_weight.merge(all[['code', 'sw1_code', 'cir_mv']]) tot_industry_sw1 = zz500_weight.groupby('sw1_code').sum() tot_industry_sw1['sw1_code'] = tot_industry_sw1.index total_mv = tot_industry_sw1['cir_mv'].sum() tot_industry_sw1[ 'industryweight_in_all'] = tot_industry_sw1['cir_mv'] / total_mv tot_industry_sw1.index.name = 'sw1_codes' # 更改level_name all = all.merge(tot_industry_sw1[['industryweight_in_all', 'sw1_code']], on='sw1_code', how='inner') # 添加申万三级行业总市值排名rank tot_industry = tot_industry.sort_values( by='cir_mv', ascending=False).reset_index(drop=True) tot_industry['rank'] = tot_industry.index + 1 all = all.merge(tot_industry[['sw3_code', 'rank']], on='sw3_code', how='inner').sort_values(by='rank').reset_index(drop=True) # 追加行业个股数量字段 count_industry = all.groupby('sw3_code').count() count_industry['indu_num'] = count_industry['code'] count_industry['sw3_code'] = count_industry.index count_industry.index.name = 'sw3_codes' all = all.merge(count_industry[['sw3_code', 'indu_num']], on='sw3_code', how='inner') # 每个行业先保留前5个 delete_list = [] indu_list = list(all['sw3_code'].unique()) for indu in indu_list: one_indu = all[all['sw3_code'] == indu] one_indu['global_index'] = one_indu.index if one_indu['indu_num'].iloc[0] > 5: one_indu = one_indu.sort_values( by='weight_in_industry', ascending=False).reset_index(drop=True) delete_list = delete_list + list(one_indu['global_index'].iloc[5:]) top5_industry = all.drop(delete_list).reset_index(drop=True) top5_industry['ten_percent'] = round(top5_industry['indu_num'] * 0.1) delete_list = [] for indu in indu_list: one_indu = top5_industry[top5_industry['sw3_code'] == indu] one_indu['global_index'] = one_indu.index if one_indu['ten_percent'].iloc[0] < 5: one_indu = one_indu.sort_values(by='weight_in_industry', ascending=False) one_indu_withoutbig = one_indu[ one_indu['weight_in_industry'] < 0.2].reset_index(drop=True) if len(one_indu_withoutbig) > 0: remain_num = one_indu_withoutbig['ten_percent'].iloc[0] \ - (len(one_indu) - len(one_indu_withoutbig)) if remain_num <= 0: delete_list = delete_list + list( one_indu_withoutbig['global_index']) else: delete_list = delete_list + \ list(one_indu_withoutbig['global_index'].iloc[int(remain_num):]) result = top5_industry.drop(delete_list).reset_index(drop=True) if top_num == None: result_top100mv = result else: result_top100mv = result[result['rank'] <= top_num] # 按成分股权重对龙头加权 hs300_weight = get_data_crosssection_genaral("huangwei", "huangwei", "index_weight", 'index_code', index_for_simple_weight) hs300_weight = hs300_weight[hs300_weight['date'] == list( hs300_weight['date'][hs300_weight['date'] >= cal_day])[0]].reset_index( drop=True) hs300_weight.rename(columns={'stock_code': 'code'}, inplace=True) # 与沪深300股票取交集 result_top100mv = result_top100mv.merge(hs300_weight[['code', 'i_weight']], on='code', how='inner') weight_sum = result_top100mv['i_weight'].sum() result_top100mv['weight_adj'] = result_top100mv['i_weight'] / weight_sum # 不与指数取交集,按照申万一级行业划分计算权重 tot_industry_sw1 = result.groupby('sw1_code').sum() tot_industry_sw1['sw1_code'] = tot_industry_sw1.index tot_industry_sw1 = tot_industry_sw1.reset_index(drop=True) result = result.merge(tot_industry_sw1[['sw1_code', 'cir_mv']], on='sw1_code', how='inner') result['weight_in_industry_sw1'] = result['cir_mv_x'] / result['cir_mv_y'] result.rename(columns={ 'cir_mv_x': 'cir_mv', 'cir_mv_y': 'industry_total_sw1' }, inplace=True) # 申万一级行业的比重*行业内部个股占整个行业的比重 result['weight_adj_sw1'] = result['industryweight_in_all'] * result[ 'weight_in_industry_sw1'] result['weight_adj_sw1'] = result['weight_adj_sw1'] / result[ 'weight_adj_sw1'].sum() # 还原cal_day # cal_day = cal_day[0:4] + cal_day[5:7] + cal_day[8:10] # file_name = 'result_' + cal_day + '.xls' # result.set_index('code').to_excel(file_name, encoding='utf-8') return result
for index, changeday in enumerate(change_days[:-2]): # 读入股票代码 all_codes = pd.read_excel( 'C:/Users/Lenovo/PycharmProjects/my_project/frjj_codes/result/industry_leader_df_md_80.xlsx', sheet_name=changeday) part_codes = pd.read_excel( 'C:/Users/Lenovo/PycharmProjects/my_project/frjj_codes/result/industry_leader_df_md_50.xlsx', sheet_name=changeday) eighty_stock = set(all_codes['code']) fifty_stock = set(part_codes['code']) maybe_bad_stock = eighty_stock.difference(fifty_stock) all_data_fifty_stock = get_data_panel("huangwei", "huangwei", list(fifty_stock), changeday, change_days[index + 1], collection='stock_daily') all_data_fifty_stock['rtn'] += 1 all_data_maybe_bad_stock = get_data_panel("huangwei", "huangwei", list(maybe_bad_stock), changeday, change_days[index + 1], collection='stock_daily') all_data_maybe_bad_stock['rtn'] += 1 # 分组计算累计收益率 fifty_stock_cum = all_data_fifty_stock.groupby( by=all_data_fifty_stock['code']).apply( lambda x: x['rtn'].cumprod().iloc[-1])
def factor_test(factor, types): # 导入股票名单和相应权重 total_capitals = [10000000] pnls = [] transaction_cost_rate = 0.003 # 交易费用 factor_list = [factor] factor_type = [types] result_export = False # 是否输出每天持仓信息 ic_weighter = True # 多因子是否按ic值加权平均 include_ir = True orthogonalization = False if result_export: result_path = './result/' # 当下根目录 strategy_name = 'industry_leader' file_name1 = strategy_name + '_df_md_80.xlsx' # 获取所有调仓日 start, end = '20180101', "20190801" change_days, my_tradingdays = get_time_data_(start, end) # 开始回测 for changeday in tqdm(list(my_tradingdays['tradingdays'])): if changeday == change_days[0]: # 建仓日 # stock_pool = GD_location_maker_(changeday) stock_pool = leader_multifactor_maker( changeday, factor_list, factor_type, ic_weighter, include_ir=include_ir, orthogonalization=orthogonalization) # stock_pool = leader_factor_maker(changeday) # 持仓矩阵初始化 position = position_init_(stock_pool, changeday, total_capitals) if result_export: # 输出持仓信息 export_result_(position, changeday, result_path, file_name1) # 记录当天的损益 pnls, total_capitals = return_maker_(position, pnls, total_capitals, transaction_cost_rate) # last_stock_pool = stock_pool_class # print(changeday, '开仓') elif changeday != change_days[0] and changeday in change_days: # 调仓日 # 更新开盘价数据 price = get_data_panel("huangwei", "huangwei", list(position['code']), changeday, changeday, collection='stock_daily').drop_duplicates( ['code']) # 保存过去的持仓情况 last_position = position if 'open' in last_position.columns: del last_position['open'] if 'rtn' in last_position.columns: del last_position['rtn'] last_position = last_position.merge(price[['code', 'open', 'rtn']], on='code', how='inner') last_position['open_price'] = last_position['open'] last_position['close_price'] = last_position['open_price'] \ * (1 + last_position['rtn']) # 按现在价格计算过去持仓的手数 last_position['lots'] = last_position['account'] / ( 100 * last_position['open_price']) last_position['lots'] = last_position['lots'].fillna( 0) # 没有开盘价的股票被“冻结” last_position['lots'] = last_position['lots'].apply( lambda x: math.floor(x)) # stock_pool = stock_select_(changeday) # stock_pool, stock_pool_class = leader_moderate(changeday, last_stock_pool, 0.02) stock_pool = leader_multifactor_maker( changeday, factor_list, factor_type, ic_weighter, include_ir=include_ir, orthogonalization=orthogonalization) # stock_pool = leader_factor_maker(changeday) # stock_pool = GD_location_maker_(changeday) # 持仓初始化 position = position_init_(stock_pool, changeday, total_capitals) position, adj_pnl = position_manager(changeday, last_position, position, transaction_cost_rate) pnls.append(adj_pnl) # 记录总价值 total_capitals.append(total_capitals[-1] + adj_pnl) # 更新每只股票的总市值 position['account_realized'] = position['account_realized'] * ( 1 + position['rtn']) position['account'] = position['account_realized'] + position[ 'account_surplus'] if result_export: # 输出持仓信息 export_result_(position, changeday, result_path, file_name1) # last_stock_pool = stock_pool_class # print(changeday, '换仓') else: # 非调仓日 # 更新价格数据 position['date'] = changeday price = get_data_panel("huangwei", "huangwei", list(position['code']), changeday, changeday, collection='stock_daily').drop_duplicates( ['code']) if 'open' in position.columns: del position['open'] if 'rtn' in position.columns: del position['rtn'] position = position.merge(price[['code', 'open', 'rtn']], on='code', how='left') position['open_price'] = position['open'] position['close_price'] = position['open_price'] * ( 1 + position['rtn']) # 计算当日持仓(可能不是正确值,因为open价格未经调整,但可以作为一个基准计算合理的收益率) position['account_realized'] = 100 * position[ 'open_price'] * position['lots'] # 记录当天的损益 temp = position.dropna(axis=0) pnl = (temp['close_price'] / temp['open_price'] - 1) * temp['account_realized'] pnls.append(pnl.sum()) # 记录总价值 total_capitals.append(total_capitals[-1] + pnl.sum()) # 更新每只股票的总市值 position['account_realized'] = position['account_realized'] * ( 1 + position['rtn']) position['account'] = position['account_realized'] + position[ 'account_surplus'] # if result_export == True: # # 输出持仓信息 # export_result_(position, changeday, result_path, file_name1) # print(changeday, '持仓') # 累计总价值曲线(与指数累计收益曲线作对比) banchmark = "000300.SH" returns = np.array(total_capitals)[1:] / np.array(total_capitals)[0] hs300 = get_data_panel( "huangwei", "huangwei", [banchmark], # 对标指数 my_tradingdays['tradingdays'].iloc[0], my_tradingdays['tradingdays'].iloc[-1], collection='index_rtn') hs300['cum_chg'] = hs300['pct_chg'] / 100 + 1 hs300['cum_chg'] = hs300['cum_chg'].cumprod().values extra = returns[:, np.newaxis] - hs300['cum_chg'].values[:, np.newaxis] performance_(hs300, banchmark, returns, extra, factor_list[0], 'spyl') return total_capitals