def summary_release_2_docx(title, img_meta_dic_list, stg_run_id=None, enable_clean_cache=True): """ 生成 预测成功率趋势报告 :param title: :param img_meta_dic_list: :param stg_run_id: :param enable_clean_cache: :return: """ logger.debug('生成报告开始') # 生成 docx 文件 document = docx.Document() # 设置默认字体 document.styles['Normal'].font.name = '微软雅黑' document.styles['Normal']._element.rPr.rFonts.set(docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 创建自定义段落样式(第一个参数为样式名, 第二个参数为样式类型, 1为段落样式, 2为字符样式, 3为表格样式) UserStyle1 = document.styles.add_style('UserStyle1', 1) # 设置字体尺寸 UserStyle1.font.size = docx.shared.Pt(40) # 设置字体颜色 UserStyle1.font.color.rgb = docx.shared.RGBColor(0xff, 0xde, 0x00) # 居中文本 UserStyle1.paragraph_format.alignment = docx.enum.text.WD_ALIGN_PARAGRAPH.CENTER # 设置中文字体 UserStyle1.font.name = '微软雅黑' UserStyle1._element.rPr.rFonts.set(docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 文件内容 document.add_heading(title, 0).alignment = docx.enum.text.WD_ALIGN_PARAGRAPH.CENTER document.add_paragraph('') document.add_paragraph('') heading_size = 1 for num, info_dic in enumerate(img_meta_dic_list, start=1): trade_date_last_train = info_dic['trade_date_last_train'] trade_date_end = info_dic['trade_date_end'] document.add_heading( f"{num}、{date_2_str(trade_date_last_train)} - {date_2_str(trade_date_end)}", heading_size) split_point_list = info_dic['split_point_list'] if split_point_list is None: p = document.add_paragraph(f"{num}.1) 日期区间段1个:\n") p.add_run(f'\t1) {date_2_str(trade_date_last_train)} ~ {date_2_str(trade_date_end)}\n') else: p = document.add_paragraph(f"{num}.1) 日期区间段{len(split_point_list) - 1}个:\n") for num2, (point1, point2) in enumerate( iter_2_range(split_point_list, has_left_outer=False, has_right_outer=False), start=1): p.add_run(f'\t{num2}) {date_2_str(point1)} ~ {date_2_str(point2)}\n') document.add_paragraph(f"{num}.2) 模型路径:\n\t{info_dic['module_file_path']}") document.add_paragraph(f"{num}.3) 取样状态(random_state):\n\t{info_dic['predict_test_random_state']}") document.add_paragraph(f"{num}.4) 展示数据长度:\n\t{info_dic['in_range_count']}") document.add_paragraph(f"{num}.5) 预测准确率趋势图:") document.add_picture(info_dic['img_file_path']) file_name = f"{title}.docx" file_path = os.path.join(get_report_folder_path(stg_run_id), file_name) document.save(file_path) if enable_clean_cache: clean_cache() logger.debug('生成报告结束。%s', file_path) return file_path
def summary_md_2_docx( md_df: pd.DataFrame, percentiles=[0.2, 0.33, 0.5, 0.66, 0.8], risk_free=0.03, close_key=None, enable_show_plot=True, enable_save_plot=False, name=None, func_kwargs_dic={}, enable_clean_cache=True, ): """ 汇总展示数据分析结果,同时以 dict 形式返回各项指标分析结果 第一个返回值,df的各项分析结果 第二个返回值,各个列的各项分析结果 :param md_df: :param percentiles:分为数信息 :param risk_free:无风险收益率 :param close_key:对哪些列的数据执行统计 :param enable_show_plot:显示plot :param enable_save_plot:保存plot :param name: :param func_kwargs_dic: :param enable_clean_cache: :return: """ ret_dic, each_col_dic, file_path_dic = summary_md( md_df, percentiles=percentiles, risk_free=risk_free, close_key=close_key, enable_show_plot=enable_show_plot, enable_save_plot=enable_save_plot, name=name, func_kwargs_dic=func_kwargs_dic) logger.debug('file_path_dic') for num, (k, v) in enumerate(file_path_dic.items(), start=1): if isinstance(v, dict): for num2, (k2, v2) in enumerate(v.items(), start=1): if isinstance(v2, dict): for num3, (k3, v3) in enumerate(v2.items(), start=1): logger.debug("%d.%d.%d) %s %s %s -> %s", num, num2, num3, k, k2, k3, v3) else: logger.debug("%d.%d) %s %s -> %s", num, num2, k, k2, v2) else: logger.debug("%d) %s -> %s", num, k, v) # 生成 docx 文档将所需变量 heading_title = f'数据分析报告 {date_2_str(min(md_df.index))} - {date_2_str(max(md_df.index))} ({md_df.shape[0]} days)' # 生成 docx 文件 document = docx.Document() # 设置默认字体 document.styles['Normal'].font.name = '微软雅黑' document.styles['Normal']._element.rPr.rFonts.set( docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 创建自定义段落样式(第一个参数为样式名, 第二个参数为样式类型, 1为段落样式, 2为字符样式, 3为表格样式) UserStyle1 = document.styles.add_style('UserStyle1', 1) # 设置字体尺寸 UserStyle1.font.size = docx.shared.Pt(40) # 设置字体颜色 UserStyle1.font.color.rgb = docx.shared.RGBColor(0xff, 0xde, 0x00) # 居中文本 UserStyle1.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # 设置中文字体 UserStyle1.font.name = '微软雅黑' UserStyle1._element.rPr.rFonts.set(docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 文件内容 document.add_heading(heading_title, 0).alignment = WD_ALIGN_PARAGRAPH.CENTER document.add_paragraph('') document.add_paragraph('') heading_count = 1 if 'warning' in ret_dic: document.add_heading(f'{heading_count}、警告信息(Warning)', 1) warning_list = ret_dic['warning'] p = document.add_paragraph('') for msg in warning_list: r = p.add_run(msg) # r.bold = True r.font.color.rgb = RGBColor(0xaf, 0x26, 0x26) p.add_run('\n') heading_count += 1 document.add_page_break() if 'rr' in file_path_dic: document.add_heading(f'{heading_count}、行情曲线', 1) # 增加图片(此处使用相对位置) document.add_picture( file_path_dic['rr']) # , width=docx.shared.Inches(1.25) heading_count += 1 # 添加分页符 document.add_page_break() if 'hist' in file_path_dic: document.add_heading(f'{heading_count}、Histgram 分布图', 1) document.add_picture(file_path_dic['hist']) heading_count += 1 if 'rr_quantile' in ret_dic: document.add_heading(f'{heading_count}、分位数信息(Quantile)', 1) rr_quantile_df = ret_dic['rr_quantile'] format_by_col = {_: FORMAT_2_PERCENT for _ in rr_quantile_df.columns} df_2_table(document, rr_quantile_df, format_by_col=format_by_col, max_col_count=5) heading_count += 1 document.add_page_break() if 'hist_future_n_rr' in file_path_dic: document.add_heading(f'{heading_count}、未来N日收益率最高最低值分布图', 1) quantile_dic = ret_dic['hist_future_n_rr']['quantile_dic'] for num, ((n_day, col_name), file_path) in enumerate( file_path_dic['hist_future_n_rr'].items(), start=1): document.add_heading( f'{heading_count}.{num}) 未来 {n_day} 日 {col_name} 收益率最高最低值分布图', 2) document.add_picture(file_path) document.add_heading(f'{heading_count}.{num}.1) 分位数信息', 3) data_df = quantile_dic[(n_day, col_name)] df_2_table( document, data_df, format_by_index={_: FORMAT_2_PERCENT for _ in data_df.index}) document.add_heading(f'{heading_count}.{num}.2) 三分类标签分布比例', 3) for (min_pct, max_pct ), distribution_rate_df in ret_dic['label_distribution'][( n_day, col_name)].items(): file_path = file_path_dic['label_distribution'][( n_day, col_name)][(min_pct, max_pct)] document.add_picture(file_path) distribution_rate_df.rename(columns={ 1: f'1 under {min_pct * 100:.2f}%', 2: f'2 over {max_pct * 100:.2f}%' }, inplace=True) df_2_table(document, distribution_rate_df, format_by_index={ _: FORMAT_2_PERCENT for _ in distribution_rate_df.index }) document.add_page_break() heading_count += 1 if 'drawdown' in file_path_dic: document.add_heading(f'{heading_count}、行情回撤曲线', 1) document.add_picture(file_path_dic['drawdown']) heading_count += 1 document.add_page_break() if 'scatter_matrix' in file_path_dic: document.add_heading(f'{heading_count}、散点图矩阵图(Scatter Matrix)', 1) document.add_picture(file_path_dic['scatter_matrix']) heading_count += 1 document.add_page_break() if 'correlation' in file_path_dic: document.add_heading(f'{heading_count}、相关性矩阵图(Correlation)', 1) document.add_picture(file_path_dic['correlation']) heading_count += 1 document.add_page_break() if 'stats' in file_path_dic: document.add_heading(f'{heading_count}、绩效统计数据(Porformance stat)', 1) stats_df = ret_dic['stats'].stats stats_df_2_docx_table(stats_df, document) heading_count += 1 document.add_page_break() # 逐列分析 col_name = close_key # 文件内容 heading_title = f'{col_name} 数据分析结果' document.add_heading(heading_title, 0).alignment = WD_ALIGN_PARAGRAPH.CENTER document.add_paragraph('') document.add_paragraph('') heading_count = 1 if 'rr_quantile' in ret_dic: document.add_heading(f'{heading_count}、分位数信息(Quantile)', 1) data_df = each_col_dic[col_name]['rr_quantile'] format_by_col = {_: FORMAT_2_PERCENT for _ in data_df.columns} df_2_table(document, data_df, format_by_col=format_by_col, max_col_count=5) heading_count += 1 if f'{col_name} hist' in file_path_dic: document.add_heading(f'{heading_count}、Histgram 分布图', 1) document.add_picture(file_path_dic[f'{col_name} hist']) heading_count += 1 document.add_page_break() # 保存文件 file_name = f"MD{' ' if name is None else ' ' + name} " \ f"{date_2_str(min(md_df.index))} - {date_2_str(max(md_df.index))} " \ f"({md_df.shape[0]} days) {datetime_2_str(datetime.datetime.now(), STR_FORMAT_DATETIME_4_FILE_NAME)}.docx" file_path = os.path.join(get_report_folder_path(), file_name) document.save(file_path) if enable_clean_cache: clean_cache() return file_path
def summary_stg_2_docx(stg_run_id=None, enable_save_plot=True, enable_show_plot=False, enable_clean_cache=True, doc_file_path=None): """ 生成策略分析报告 :param stg_run_id: :param enable_save_plot: :param enable_show_plot: :param enable_clean_cache: :param doc_file_path: 可以是目录 或 文件名路径 :return: """ info = get_stg_run_info(stg_run_id) stg_run_id = info.stg_run_id stg_name = info.stg_name run_mode = RunMode(info.run_mode) kwargs = { "enable_show_plot": enable_show_plot, "enable_save_plot": enable_save_plot, "run_mode": run_mode, "stg_run_id": stg_run_id } if run_mode == RunMode.Backtest_FixPercent: sum_df, symbol_rr_dic = get_rr_with_md(stg_run_id, compound_rr=True) else: sum_df, symbol_rr_dic = get_rr_with_md(stg_run_id, compound_rr=False) if sum_df is None or sum_df.shape[0] == 0: logger.warning('stg_run_id=%d 没有获取到 sum_df', stg_run_id) file_path = None return file_path ret_dic, each_col_dic, file_path_dic = summary_rr(sum_df, **kwargs) _, file_path = show_trade(**kwargs) file_path_dic['trade'] = file_path df, file_path = show_cash_and_margin(**kwargs) file_path_dic['cash_and_margin'] = file_path # 生成 docx 文档将所需变量 heading_title = f'策略分析报告[{stg_run_id} {stg_name}] ' \ f'{date_2_str(min(sum_df.index))} - {date_2_str(max(sum_df.index))} ({sum_df.shape[0]} days)' # 生成 docx 文件 document = docx.Document() # 设置默认字体 document.styles['Normal'].font.name = '微软雅黑' document.styles['Normal']._element.rPr.rFonts.set( docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 创建自定义段落样式(第一个参数为样式名, 第二个参数为样式类型, 1为段落样式, 2为字符样式, 3为表格样式) UserStyle1 = document.styles.add_style('UserStyle1', 1) # 设置字体尺寸 UserStyle1.font.size = docx.shared.Pt(40) # 设置字体颜色 UserStyle1.font.color.rgb = docx.shared.RGBColor(0xff, 0xde, 0x00) # 居中文本 UserStyle1.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER # 设置中文字体 UserStyle1.font.name = '微软雅黑' UserStyle1._element.rPr.rFonts.set(docx.oxml.ns.qn('w:eastAsia'), '微软雅黑') # 文件内容 document.add_heading(heading_title, 0).alignment = WD_ALIGN_PARAGRAPH.CENTER document.add_paragraph('') document.add_paragraph('') heading_count = 1 document.add_heading(f'{heading_count}、策略回测收益曲线', 1) # 增加图片(此处使用相对位置) document.add_picture( file_path_dic['rr']) # , width=docx.shared.Inches(1.25) heading_count += 1 # 添加分页符 document.add_page_break() document.add_heading(f'{heading_count}、策略回撤曲线', 1) document.add_picture(file_path_dic['drawdown']) heading_count += 1 document.add_page_break() if run_mode != RunMode.Backtest_FixPercent: document.add_heading(f'{heading_count}、现金与仓位堆叠图', 1) document.add_picture(file_path_dic['cash_and_margin']) heading_count += 1 document.add_page_break() document.add_heading(f'{heading_count}、散点图矩阵图(Scatter Matrix)', 1) document.add_picture(file_path_dic['scatter_matrix']) heading_count += 1 document.add_page_break() document.add_heading(f'{heading_count}、相关性矩阵图(Correlation)', 1) document.add_picture(file_path_dic['correlation']) heading_count += 1 document.add_page_break() document.add_heading(f'{heading_count}、绩效统计数据(Porformance stat)', 1) stats_df = ret_dic['stats'].stats stats_df_2_docx_table(stats_df, document) heading_count += 1 document.add_page_break() # 交易记录 document.add_heading(f'{heading_count}、买卖点记录', 1) document.add_picture(file_path_dic['trade']) heading_count += 1 document.add_page_break() # 保存文件 if doc_file_path is not None: if os.path.isdir(doc_file_path): folder_path, file_name = doc_file_path, '' else: folder_path, file_name = os.path.split(doc_file_path) else: folder_path, file_name = get_report_folder_path(stg_run_id), '' if folder_path != '' and not os.path.exists(folder_path): os.makedirs(folder_path) if file_name == '': try: calc_mode_str = CalcMode( json.loads( info.trade_agent_params_list)[0]['calc_mode']).name + " " except: calc_mode_str = " " # run_mode_str = run_mode.name + " " file_name = f"{stg_run_id} {stg_name} {calc_mode_str}" \ f"{date_2_str(min(sum_df.index))} - {date_2_str(max(sum_df.index))} ({sum_df.shape[0]} days) " \ f"{datetime_2_str(datetime.datetime.now(), STR_FORMAT_DATETIME_4_FILE_NAME)}.docx" file_path = os.path.join(folder_path, file_name) else: file_path = doc_file_path document.save(file_path) if enable_clean_cache: clean_cache() return file_path