def run(self): start_time = datetime.datetime.now() self.initialize_strategy() self.code_range = self.code_range.loc[self.code_range['industry'] == '银行(中信)'] self.code_range.reset_index(inplace=True) overall_factor = self.factors_combination() selection = self.select_codes(overall_factor) selection.to_csv(self.folder_dir + 'code_selection.csv', encoding='gbk') bm_stk_wgt = self.get_next_bm_stk_wgt() bm_stk_wgt.to_csv(self.folder_dir + 'bm_wgt.csv', encoding='gbk') # --------------------------backtest-------------------------------- bt_start = selection.index[0].strftime('%Y%m%d') bt_end = bm_stk_wgt.index[-1].strftime('%Y%m%d') QE = BacktestEngine(self.strategy_name, bt_start, bt_end, self.adj_interval, self.benchmark, stock_capital=self.capital) pvs = [] portfolio_value = QE.run(selection, bt_start, bt_end) portfolio_value = portfolio_value.loc[:, ['TotalValue']] portfolio_value.rename(columns={'TotalValue': 'AlphaBank'}, inplace=True) pvs.append(portfolio_value) QE.stk_portfolio.reset_portfolio(self.capital) portfolio_value = QE.run(bm_stk_wgt, bt_start, bt_end) portfolio_value = portfolio_value.loc[:, ['TotalValue']] portfolio_value.rename(columns={'TotalValue': 'BmBank'}, inplace=True) pvs.append(portfolio_value) banks_comparation = pd.concat(pvs, axis=1) banks_comparation['AccumAlpha'] = \ DataProcess.calc_accum_alpha(banks_comparation['AlphaBank'], banks_comparation['BmBank']) - 1 banks_comparation.to_csv(self.folder_dir + 'banks_comaration.csv', encoding='gbk') self.logger.info('Bank Comparation:') self.logger.info('-ANN_Alpha: %f' % DataProcess.calc_alpha_ann_return( banks_comparation['AlphaBank'], banks_comparation['BmBank'])) MDD, MDD_period = \ DataProcess.calc_alpha_max_draw_down(banks_comparation['AlphaBank'], banks_comparation['BmBank']) self.logger.info('-Alpha_MDD: %f' % MDD) self.logger.info('-Alpha_MDD period: %s - %s' % (MDD_period[0], MDD_period[1])) self.logger.info('-Alpha_sharpe: %f' % DataProcess.calc_alpha_sharpe( banks_comparation['AlphaBank'], banks_comparation['BmBank'])) print('Time used:', datetime.datetime.now() - start_time)
def group_backtest(self, grouped_weight): group = [] BE = BacktestEngine('FactorTest_{0}'.format(self.save_name), self.start, self.end, self.adj_interval, self.benchmark, stock_capital=self.capital, logger_lvl=logging.DEBUG) for i in range(1, self.groups + 1): group.append('group_' + str(i)) start = grouped_weight.index.unique().strftime('%Y%m%d')[0] end = grouped_weight.index.unique().strftime('%Y%m%d')[-1] pvs = [] for g in group: weight = grouped_weight.loc[ (grouped_weight['group'] == g) | (grouped_weight['group'] == 'same_group'), ['code', 'weight']].copy() portfolio_value, _ = BE.run(weight, start, end) portfolio_value = portfolio_value.loc[:, ['TotalValue', 'BenchmarkValue', 'AccumAlpha']] portfolio_value.rename(columns={'TotalValue': 'TotalValue_{0}'.format(g), 'BenchmarkValue': 'BenchmarkValue_{0}'.format(g), 'AccumAlpha': 'AccumAlpha_{0}'.format(g)}, inplace=True) pvs.append(portfolio_value) # 重置 stk_portfolio BE.stk_portfolio.reset_portfolio(self.capital) tot_res = pd.concat(pvs, axis=1) tot_res['long_short'] = tot_res['TotalValue_{0}'.format(group[-1])].pct_change().fillna(0) - \ tot_res['TotalValue_{0}'.format(group[0])].pct_change().fillna(0) tot_res['long_short'] = (tot_res['long_short'] + 1).cumprod() folder_dir = global_constant.ROOT_DIR + '/Factor_Test/{0}/'.format(self.save_name) tot_res.to_csv(folder_dir + 'Value_{0}to{1}.csv'.format(self.start, self.end), encoding='gbk') print('-' * 30) # ------------------------------------- self.summary_dict['Start_Time'] = start self.summary_dict['End_Time'] = end self.summary_dict['AnnAlpha'] = DataProcess.calc_alpha_ann_return( tot_res['TotalValue_{0}'.format(group[-1])], tot_res['BenchmarkValue_{0}'.format(group[-1])]) self.summary_dict['AlphaMDD'] = DataProcess.calc_alpha_max_draw_down( tot_res['TotalValue_{0}'.format(group[-1])], tot_res['BenchmarkValue_{0}'.format(group[-1])]) self.summary_dict['AlphaSharpe'] = DataProcess.calc_alpha_sharpe( tot_res['TotalValue_{0}'.format(group[-1])], tot_res['BenchmarkValue_{0}'.format(group[-1])]) return self.summary_dict.copy()
def all_indu_run(self, stk_weight, start, end): # folder if os.path.exists(self.dir + '/industry_alpha/'): pass else: os.makedirs(self.dir + '/industry_alpha') # logger self.indu_logger = logging.getLogger('industry_log') self.indu_logger.setLevel(level=logging.INFO) file_name = 'industry.log' handler = logging.FileHandler(self.dir + '/industry_alpha/' + file_name) handler.setLevel(logging.INFO) console = logging.StreamHandler() formatter = logging.Formatter( '%(asctime)s - %(levelname)s: %(message)s') handler.setFormatter(formatter) handler.setFormatter(formatter) self.indu_logger.addHandler(handler) self.indu_logger.addHandler(console) # industry 为统计用数据 measure = 'industry' industry = self.influx.getDataMultiprocess(self.DB, measure, self.start, self.end, ['code', self.indu_field]) industry.index.names = ['date'] industry.rename(columns={self.indu_field: 'industry'}, inplace=True) # benchmark comp measure = 'index_weight' bm_comp = self.influx.getDataMultiprocess(self.DB, measure, self.start, self.end) bm_comp = bm_comp.loc[bm_comp['index_code'] == self.benchmark_code, ['code', 'weight']] former_date_dict = dict( zip(bm_comp.index.unique()[1:], bm_comp.index.unique()[:-1])) bm_comp['date'] = bm_comp.index bm_comp['date'] = bm_comp['date'].map(former_date_dict) bm_comp = bm_comp.dropna(subset=['date']) bt_start = max(bm_comp.index.unique()[0], stk_weight.index.unique()[0], pd.to_datetime(str(start))) bt_end = min(bm_comp.index.unique()[-1], stk_weight.index.unique()[-1], pd.to_datetime(str(end))) # merge industry bm_comp = pd.merge(bm_comp, industry.reset_index(), on=['date', 'code']) stk_weight = pd.merge(stk_weight.reset_index(), industry.reset_index(), on=['date', 'code']) for indu in bm_comp['industry'].unique(): bm_comp_indu = bm_comp.loc[bm_comp['industry'] == indu, ['date', 'code', 'weight']].copy() indu_weight = bm_comp_indu.groupby( 'date')['weight'].sum().to_dict() bm_comp_indu['bm_weight'] = bm_comp_indu['date'].map(indu_weight) bm_comp_indu['weight'] = bm_comp_indu['weight'] / bm_comp_indu[ 'bm_weight'] * 100 bm_comp_indu = bm_comp_indu.loc[:, ['date', 'code', 'weight']] bm_comp_indu.set_index('date', inplace=True) stk_weight_indu = stk_weight.loc[ stk_weight['industry'] == indu, ['date', 'code', 'weight']].copy() indu_weight = stk_weight_indu.groupby( 'date')['weight'].sum().to_dict() stk_weight_indu['bm_weight'] = stk_weight_indu['date'].map( indu_weight) stk_weight_indu['weight'] = stk_weight_indu[ 'weight'] / stk_weight_indu['bm_weight'] * 100 stk_weight_indu = stk_weight_indu.loc[:, ['date', 'code', 'weight']] stk_weight_indu.set_index('date', inplace=True) # =========================================================================================== bm_value, _ = self.run(bm_comp_indu, bt_start, bt_end, 'bm_{0}'.format(indu)) self.stk_portfolio.reset_portfolio(self.stock_capital) alpha_value, _ = self.run(stk_weight_indu, bt_start, bt_end, 'alpha_{0}'.format(indu)) self.stk_portfolio.reset_portfolio(self.stock_capital) bm_value.rename(columns={'TotalValue': 'BmStkValue'}, inplace=True) bm_value = bm_value.loc[:, ['BmStkValue']] alpha_value.rename(columns={'TotalValue': 'AlphaValue'}, inplace=True) alpha_value = alpha_value.loc[:, ['AlphaValue']] merge_value = pd.merge(bm_value.reset_index(), alpha_value.reset_index(), on=['date']) merge_value['AccumAlpha'] = \ DataProcess.calc_accum_alpha(merge_value['AlphaValue'], merge_value['BmStkValue']) - 1 merge_value.set_index('date', inplace=True) filename = self.dir + '/industry_alpha/{0}.csv'.format(indu) merge_value.to_csv(filename, encoding='gbk') self.indu_logger.info('INDUSTRY: {0}'.format(indu)) self.indu_logger.info( '-ANN_Alpha: %f' % DataProcess.calc_alpha_ann_return( merge_value['AlphaValue'], merge_value['BmStkValue'])) MDD, MDD_period = DataProcess.calc_alpha_max_draw_down( merge_value['AlphaValue'], merge_value['BmStkValue']) self.indu_logger.info('-Alpha_MDD: %f' % MDD) self.indu_logger.info('-Alpha_MDD period: %s - %s' % (MDD_period[0], MDD_period[1])) self.indu_logger.info( '-Alpha_sharpe: %f' % DataProcess.calc_alpha_sharpe( merge_value['AlphaValue'], merge_value['BmStkValue'])) self.indu_logger.info('-' * 50)
def run(self, stk_weight, start, end, name=None): backtest_starttime = datetime.datetime.now() # 默认输入的权重 以日期为index stk_weight.index.names = ['date'] mkt = self.market.loc[str(start):str(end), :].copy() mkt_with_weight = pd.merge(mkt.reset_index(), stk_weight.reset_index(), on=['date', 'code'], how='left') mkt_with_weight['weight'] = mkt_with_weight['weight'].fillna(0) mkt_with_weight.set_index('date', inplace=True) mkt_with_weight.sort_index(inplace=True) calendar = mkt_with_weight.index.unique().strftime('%Y%m%d') # backtest begins day_counter = 0 positions_dict = {} portfolio_value_dict = {} balance, stk_value, total_value = self.stk_portfolio.get_portfolio_value( price_input=pd.Series([])) # 记录 benchmark 净值 benchmark_networth = self.benchmark_quote[calendar[0]] benchmark_start_value = total_value for trade_day in calendar: self.logger.info('Trade Day: %s' % trade_day) day_mkt_with_weight = mkt_with_weight.loc[mkt_with_weight.index == trade_day, :].copy() day_mkt_with_weight.set_index('code', inplace=True) day_ex_right = self.exright.loc[self.exright.index == trade_day, :].copy() trade_amount = 0 # 开盘前处理除权除息分红送股 self.stk_portfolio.process_ex_right(day_ex_right) # 没有行情且在position里的stk记为退市,并统计退市金额 delist_amount = 0 no_quote_stks = set(self.stk_portfolio.stk_positions.keys()) - set( day_mkt_with_weight.index) for stk in no_quote_stks: delist_amount += self.stk_portfolio.stk_positions[stk]['volume'] * \ self.stk_portfolio.stk_positions[stk]['latest_close'] # 退市股票的金额需在stock_value中剔除,以免资金占用 target_capital = (1 - self.cash_reserve_rate) * (total_value + delist_amount) # 计算目标成交量 day_mkt_with_weight['target_volume'] = \ target_capital * day_mkt_with_weight['weight'] / 100 / day_mkt_with_weight['preclose'] # ----------------------------------------------------------------------------------------------- # 每隔x天调仓 if day_counter % self.adj_interval == 0: # 记录没法交易的股票 # 记录 (weight不为0 或者 已在position中) 且 状态停牌 的票 codes = day_mkt_with_weight.loc[ ((day_mkt_with_weight['target_volume'] > 0) | (day_mkt_with_weight.index.isin(self.stk_portfolio. stk_positions.keys()))) & (day_mkt_with_weight['status'] == '停牌'), :].index.values weights = day_mkt_with_weight.loc[ ((day_mkt_with_weight['target_volume'] > 0) | (day_mkt_with_weight.index.isin(self.stk_portfolio. stk_positions.keys()))) & (day_mkt_with_weight['status'] == '停牌'), 'weight'].values untradeable = dict(zip(codes, weights)) # (weight不为0 或者 已在position中) 且 状态不停牌 的票 tradeable_df = day_mkt_with_weight.loc[ ((day_mkt_with_weight['target_volume'] > 0) | (day_mkt_with_weight.index.isin(self.stk_portfolio. stk_positions.keys()))) & (day_mkt_with_weight['status'] != '停牌'), :].copy() for code, row in tradeable_df.iterrows(): if (row['low'] == row['high']) and (row['high'] >= round( row['preclose'] * 1.1, 2)): price_limit = 'high' elif (row['low'] == row['high']) and (row['low'] <= round( row['preclose'] * 0.9, 2)): price_limit = 'low' else: price_limit = 'no_limit' # 因涨跌停没有交易成功的股票代码会返回 trade_res = self.stk_portfolio.trade_stks_to_target_volume( trade_day, code, row[self.price_field], row['target_volume'], price_limit) # 记录可以交易,但是因为涨跌停无法交易 的票 if trade_res == 'Trade Fail': untradeable[code] = row['weight'] # 记录双边的交易金额 else: trade_amount += trade_res # 不是调仓日时,之前因涨跌停没买到的stks也要补 else: # 没有行情的认为已退市,从失败列表中剔除 no_quote_in_untradeable = set(untradeable.keys()) - set( day_mkt_with_weight.index) for stk in no_quote_in_untradeable: untradeable.pop(stk) # untradeable 不为空时,补买卖stk if untradeable: tradeable_df = day_mkt_with_weight.loc[ (day_mkt_with_weight['status'] != '停牌') & day_mkt_with_weight.index.isin(untradeable.keys() ), :].copy() if not tradeable_df.empty: tradeable_df['weight'] = tradeable_df.index tradeable_df['weight'] = tradeable_df['weight'].map( untradeable) tradeable_df['target_volume'] = \ target_capital * tradeable_df['weight'] / 100 / tradeable_df['preclose'] for code, row in tradeable_df.iterrows(): if (row['low'] == row['high']) and (row['high'] >= round( row['preclose'] * 1.1, 2)): price_limit = 'high' elif (row['low'] == row['high']) and (row['low'] <= round( row['preclose'] * 0.9, 2)): price_limit = 'low' else: price_limit = 'no_limit' trade_res = self.stk_portfolio.trade_stks_to_target_volume( trade_day, code, row[self.price_field], row['target_volume'], price_limit) if trade_res == 'Trade Fail': pass else: trade_amount += trade_res untradeable.pop(code) # ------------------------------------------------------------------------------- # 处理 吸收合并 day_swap = self.swap.loc[ self.swap['code'].isin(self.stk_portfolio.stk_positions.keys()) & (self.swap.index == trade_day), :].copy() if not day_swap.empty: for date, row in day_swap.iterrows(): swap_price = self.stk_portfolio.stk_positions[ row['code']]['price'] / row['swap_ratio'] swap_volume = round( self.stk_portfolio.stk_positions[row['code']]['volume'] * row['swap_ratio']) if row['swap_code'] in self.stk_portfolio.stk_positions: merged_volume = self.stk_portfolio.stk_positions[ row['swap_code']]['volume'] + swap_volume merged_price = ( self.stk_portfolio.stk_positions[row['swap_code']] ['volume'] * self.stk_portfolio.stk_positions[ row['swap_code']]['price'] + swap_volume * swap_price) / merged_volume self.stk_portfolio.stk_positions[ row['swap_code']]['volume'] = merged_volume self.stk_portfolio.stk_positions[ row['swap_code']]['price'] = merged_price else: self.stk_portfolio.stk_positions[row['swap_code']] = {} self.stk_portfolio.stk_positions[ row['swap_code']]['volume'] = swap_volume self.stk_portfolio.stk_positions[ row['swap_code']]['price'] = swap_price self.stk_portfolio.stk_positions[row['swap_code']]['latest_close'] = \ self.stk_portfolio.stk_positions[row['code']]['latest_close'] / row['swap_ratio'] self.stk_portfolio.stk_positions.pop(row['code']) # 记录 已有持仓中停牌的stk suspend_stks_in_pos = \ day_mkt_with_weight.loc[ day_mkt_with_weight.index.isin(self.stk_portfolio.stk_positions.keys()) & (day_mkt_with_weight['status'] == '停牌'), :].index.values # 记录 benchmark value # 记录 portfolio value # 记录双边换手率 turnover benchmark_value = benchmark_start_value / benchmark_networth * self.benchmark_quote[ trade_day] balance, stk_value, total_value = self.stk_portfolio.get_portfolio_value( day_mkt_with_weight['close']) if stk_value == 0: turnover = 0 else: turnover = trade_amount / stk_value portfolio_value_dict[trade_day] = \ {'Balance': balance, 'StockValue': stk_value, 'TotalValue': total_value, 'DelistAmount': delist_amount, 'SuspendStk': len(suspend_stks_in_pos), 'BenchmarkValue': benchmark_value, 'Turnover': turnover} self.logger.info( ' -Balance: %f \n -StockValue: %f \n -TotalValue %f \n -DelistAmount: %f \n' ' -SuspendStk: %i \n -BenchmarkValue: %f \n -Turnover: %f' % (balance, stk_value, total_value, delist_amount, len(suspend_stks_in_pos), benchmark_value, turnover)) self.logger.info( '=======================================================================' ) # 记录 持仓 positions_dict[trade_day] = copy.deepcopy( self.stk_portfolio.stk_positions) day_counter += 1 # 输出持仓记录 positions_dfs = [] for time in positions_dict: trade_day_position = pd.DataFrame(positions_dict[time]).T trade_day_position['Time'] = time trade_day_position.index.name = 'Code' positions_dfs.append(trade_day_position.reset_index()) positions = pd.concat(positions_dfs, ignore_index=True) positions['Time'] = pd.to_datetime(positions['Time']) positions.set_index('Time', inplace=True) if not name: filename = self.dir + 'Positions.csv' else: filename = self.dir + 'Positions_{0}.csv'.format(name) positions.to_csv(filename, encoding='gbk') # 输出净值 portfolio_value = pd.DataFrame(portfolio_value_dict).T portfolio_value['AccumAlpha'] = \ DataProcess.calc_accum_alpha(portfolio_value['TotalValue'], portfolio_value['BenchmarkValue']) - 1 portfolio_value.index = pd.to_datetime(portfolio_value.index) portfolio_value.index.names = ['date'] if not name: filename = self.dir + 'Value.csv' else: filename = self.dir + 'Value_{0}.csv'.format(name) portfolio_value.to_csv(filename, encoding='gbk') self.res_logger.info( 'Backtest finish time: %s' % datetime.datetime.now().strftime('%Y/%m/%d - %H:%M:%S')) self.res_logger.info('*' * 50) self.res_logger.info('{0} PERFORMANCE:'.format(name)) self.res_logger.info('-ANN_Alpha: %f' % DataProcess.calc_alpha_ann_return( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) MDD, MDD_period = DataProcess.calc_alpha_max_draw_down( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue']) self.res_logger.info('-Alpha_MDD: %f' % MDD) self.res_logger.info('-Alpha_MDD period: %s - %s' % (MDD_period[0], MDD_period[1])) self.res_logger.info( '-Alpha_sharpe: %f' % DataProcess.calc_alpha_sharpe(portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) print('Backtest finish! Time used: ', datetime.datetime.now() - backtest_starttime) return portfolio_value, positions
def run(self): start_time = datetime.datetime.now() # -----------------------------get data------------------------------ # 银行因子 print('BANK Factors processing...') overall_bank = self.factors_combination(CATEGORY_BANK, FACTOR_BANK, '银行(中信)') overall_bank.to_csv(self.folder_dir + 'factors_bank.csv', encoding='gbk') overall_bank = overall_bank.loc[:, ['code', 'overall']] bm_bank = self.get_bm_idsty_wgt('银行(中信)') # 券商因子 print('SEC Factors processing...') overall_sec = self.factors_combination(CATEGORY_SEC, FACTOR_SEC, '证券Ⅱ(中信)') overall_sec.to_csv(self.folder_dir + 'factors_sec.csv', encoding='gbk') overall_sec = overall_sec.loc[:, ['code', 'overall']] bm_sec = self.get_bm_idsty_wgt('证券Ⅱ(中信)') # 非金融因子 print('NON FIN Factors processing...') overall_non_fin = self.factors_combination(CATEGORY_NON_FIN, FACTOR_NON_FIN, None) overall_non_fin.to_csv(self.folder_dir + 'factors_non_fin.csv', encoding='gbk') overall_non_fin = overall_non_fin.loc[:, ['code', 'overall']] bm_non_fin = self.get_bm_idsty_wgt(None) print('ALL Factors finish!') # ---------------------------opt_weight------------------------------ # 银行权重 print('BANK Opt processing...') opt_bank_wgt = self.opt_weight(overall_bank, bm_bank, self.bank_const, self.bank_ratio) bank_tot_wgt = bm_bank.reset_index().drop_duplicates(['date']) bank_tot_wgt = bank_tot_wgt.loc[:, ['date', 'tot_wgt']] bank_tot_wgt = dict(zip(bank_tot_wgt['date'], bank_tot_wgt['tot_wgt'])) opt_bank_wgt['bank_wgt'] = opt_bank_wgt.index opt_bank_wgt['bank_wgt'] = opt_bank_wgt['bank_wgt'].map(bank_tot_wgt) opt_bank_wgt['weight'] = np.round( opt_bank_wgt['weight'] / 100 * opt_bank_wgt['bank_wgt'], 2) # opt_bank_wgt.to_csv(self.folder_dir + 'bank_weight.csv', encoding='gbk') # 券商权重 print('SEC Opt processing...') # 行业内权重 opt_sec_wgt = self.opt_weight(overall_sec, bm_sec, self.sec_const, self.sec_ratio) sec_tot_wgt = bm_sec.reset_index().drop_duplicates(['date']) sec_tot_wgt = sec_tot_wgt.loc[:, ['date', 'tot_wgt']] sec_tot_wgt = dict(zip(sec_tot_wgt['date'], sec_tot_wgt['tot_wgt'])) opt_sec_wgt['sec_wgt'] = opt_sec_wgt.index opt_sec_wgt['sec_wgt'] = opt_sec_wgt['sec_wgt'].map(sec_tot_wgt) opt_sec_wgt['weight'] = np.round( opt_sec_wgt['weight'] / 100 * opt_sec_wgt['sec_wgt'], 2) # 非金融权重 print('NON FIN Opt processing...') opt_non_fin_wgt = self.opt_weight(overall_non_fin, bm_non_fin, self.non_fin_const, self.non_fin_ratio) # 组合权重 target_weight = pd.concat([ opt_bank_wgt.reset_index(), opt_sec_wgt.reset_index(), opt_non_fin_wgt.reset_index() ], ignore_index=True) target_weight = target_weight.set_index('date') target_weight = target_weight.sort_index() target_weight.to_csv(self.folder_dir + 'target_weight.csv', encoding='gbk') print('target_weight is ready!') # --------------------------backtest-------------------------------- bt_start = target_weight.index[0].strftime('%Y%m%d') bt_end = (target_weight.index[-1]).strftime('%Y%m%d') QE = BacktestEngine(self.strategy_name, bt_start, bt_end, self.adj_interval, self.benchmark, stock_capital=self.capital) portfolio_value, _ = QE.run(target_weight, bt_start, bt_end) self.logger.info( 'Strategy finish time: %s' % datetime.datetime.now().strftime('%Y/%m/%d - %H:%M:%S')) self.logger.info('*' * 50) self.logger.info('PERFORMANCE:') self.logger.info('-ANN_Alpha: %f' % DataProcess.calc_alpha_ann_return( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) MDD, MDD_period = \ DataProcess.calc_alpha_max_draw_down(portfolio_value['TotalValue'], portfolio_value['BenchmarkValue']) self.logger.info('-Alpha_MDD: %f' % MDD) self.logger.info('-Alpha_MDD period: %s - %s' % (MDD_period[0], MDD_period[1])) self.logger.info('-Alpha_sharpe: %f' % DataProcess.calc_alpha_sharpe( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) print('Time used:', datetime.datetime.now() - start_time)
def run(self): start_time = datetime.datetime.now() # -----------------------------get data------------------------------ self.initialize_strategy() # 使用 risk 中的 Size,避免不同的 size 造成误差 # range_z_size = self.get_z_size() overall_factor = self.factors_combination() next_bm_stk_wgt = self.get_next_bm_stk_wgt() # get base weight base_weight = self.get_base_weight(overall_factor, next_bm_stk_wgt) # get target weight dates = base_weight.index.unique().strftime("%Y%m%d") split_dates = np.array_split(dates, self.n_jobs) with parallel_backend('multiprocessing', n_jobs=self.n_jobs): parallel_res = \ Parallel()(delayed(alpha_version_3.JOB_opti_weight) (base_weight, self.risk_cov, self.indus, self.risks, dates, self.adj_interval, self.target_sigma, self.mv_max_exp, self.mv_min_exp, self.weight_intercept) for dates in split_dates) parallel_dfs = [] fail_dates = [] for res in parallel_res: parallel_dfs.append(res[0]) fail_dates.extend(res[1]) target_weight = pd.concat(parallel_dfs) target_weight.to_csv(self.folder_dir + 'RAW_TARGET_WEIGHT.csv', encoding='gbk') print('raw weight is ready...') target_weight = target_weight.sort_index() # ------------------------limit n_codes----------------------------- stk_count = target_weight.groupby('date')['code'].count() dates = target_weight.index.unique().strftime('%Y%m%d') split_dates = np.array_split(dates, self.n_jobs) with parallel_backend('multiprocessing', n_jobs=self.n_jobs): parallel_res = Parallel()(delayed(alpha_version_3.JOB_limit_n_stk) (target_weight, dates, stk_count, self.n_codes, next_bm_stk_wgt) for dates in split_dates) target_weight = pd.concat(parallel_res) target_weight = target_weight.sort_index() # ----------------------fill target weight-------------------------- if fail_dates: fill_df = alpha_version_3.JOB_fill_df(target_weight, fail_dates, next_bm_stk_wgt) target_weight = pd.concat([target_weight, fill_df]) target_weight = target_weight.sort_index() # ---------------------------date shift----------------------------- target_weight = self.shift_target_weight(target_weight) # ------------------------------------------------------------------ target_weight.to_csv(self.folder_dir + 'TARGET_WEIGHT.csv', encoding='gbk') print('target_weight is ready...') # --------------------------backtest-------------------------------- bt_start = target_weight.index[0].strftime('%Y%m%d') bt_end = (target_weight.index[-1] - datetime.timedelta(days=1)).strftime('%Y%m%d') QE = BacktestEngine(self.strategy_name, bt_start, bt_end, self.adj_interval, self.benchmark, stock_capital=self.capital) portfolio_value = QE.run(target_weight, bt_start, bt_end) self.logger.info('Strategy finish time: %s' % datetime.datetime.now().strftime('%Y/%m/%d - %H:%M:%S')) self.logger.info('*' * 50) self.logger.info('PERFORMANCE:') self.logger.info('-ANN_Alpha: %f' % DataProcess.calc_alpha_ann_return( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) MDD, MDD_period = \ DataProcess.calc_alpha_max_draw_down(portfolio_value['TotalValue'], portfolio_value['BenchmarkValue']) self.logger.info('-Alpha_MDD: %f' % MDD) self.logger.info('-Alpha_MDD period: %s - %s' % (MDD_period[0], MDD_period[1])) self.logger.info('-Alpha_sharpe: %f' % DataProcess.calc_alpha_sharpe( portfolio_value['TotalValue'], portfolio_value['BenchmarkValue'])) print('Time used:', datetime.datetime.now() - start_time)