克隆策略

    {"description":"实验创建于2017/8/26","graph":{"edges":[{"to_node_id":"-726:features","from_node_id":"-331:data"},{"to_node_id":"-143:input_2","from_node_id":"-726:data"},{"to_node_id":"-34:factors_info","from_node_id":"-143:data_1"},{"to_node_id":"-726:instruments","from_node_id":"-460:data"},{"to_node_id":"-143:input_1","from_node_id":"-460:data"},{"to_node_id":"-143:input_3","from_node_id":"-47:data"}],"nodes":[{"node_id":"-331","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"factor=np.corrcoef(close.pct_change().fillna(0),amount)[0][1]\n\n","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-331"}],"output_ports":[{"name":"data","node_id":"-331"}],"cacheable":true,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-726","module_id":"BigQuantSpace.feature_extractor_1m.feature_extractor_1m-v2","parameters":[{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"before_start_days","value":"60","type":"Literal","bound_global_parameter":null},{"name":"workers","value":"1","type":"Literal","bound_global_parameter":null},{"name":"parallel_mode","value":"集群","type":"Literal","bound_global_parameter":null},{"name":"table_1m","value":"bar1m_CN_FUTURE","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-726"},{"name":"features","node_id":"-726"},{"name":"user_functions","node_id":"-726"}],"output_ports":[{"name":"data","node_id":"-726"}],"cacheable":true,"seq_num":14,"comment":"","comment_collapsed":true},{"node_id":"-34","module_id":"BigQuantSpace.factorlens_preservation.factorlens_preservation-v1","parameters":[],"input_ports":[{"name":"factors_info","node_id":"-34"}],"output_ports":[{"name":"data","node_id":"-34"}],"cacheable":true,"seq_num":3,"comment":"","comment_collapsed":true},{"node_id":"-143","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\nfrom datetime import datetime\nimport time\nimport bigexpr\n\n \n\nclass FuturesPerformance:\n def __init__(self,start_date=None,end_date=None,rabalance_period=22,buy_commission_rate=0.0005,sell_commission_rate=0.0005,ic_method=\"Rank_IC\",quantile_num=5,is_standardlize=True,is_winsorize=True):\n \n \n self.start_date = start_date\n self.end_date = end_date\n self.rabalance_period = rabalance_period # 调仓天数\n self.buy_commission_rate = buy_commission_rate # 买入佣金(百分比)\n self.sell_commission_rate = sell_commission_rate # 卖出佣金(百分比)\n self.ic_method = ic_method\n self.quantile_num = quantile_num\n self.is_standardlize = is_standardlize # 是否标准化\n self.is_winsorize = is_winsorize # 是否去极值\n\n def data_processing(self, continus_contract_df, factor_name):\n # 表达式抽取\n start_time = time.time()\n\n\n def _handle_data(df, factor_name, price_type):\n # 计算当期因子和未来一段时间收益率\n # df[\"factor\"] = df[\"close\"] / df[\"close\"].shift(44) - 1 # 构建因子\n df[\"factor\"] = df[factor_name]\n\n # 持有期收益率\n df[\"ret\"] = df[price_type].shift(-1 * self.rabalance_period) / df[price_type] - 1\n df['ret'] = df.ret.shift(-1) # 下一期的收益率\n df['daily_ret_1'] = df['close'].pct_change().shift(-1) # 次日收益率\n return df\n\n # 极值数据处理\n def _winsorize(df):\n df = df.copy()\n factor_columns = [\"factor\"]\n for factor in factor_columns:\n mean = df[factor].mean()\n sigma = df[factor].std()\n df[factor] = df[factor].clip(mean - 3 * sigma, mean + 3 * sigma)\n return df\n\n # 标准数据处理\n def _standardlize(df):\n df = df.copy()\n factor_columns = [\"factor\"]\n for factor in factor_columns:\n mean = df[factor].mean()\n sigma = df[factor].std()\n df[factor] = (df[factor] - mean) / sigma\n return df\n \n factor_df_with_ret = continus_contract_df.groupby(\"instrument\").apply(_handle_data, factor_name=factor_name, price_type=\"close\")\n \n base_factor_df = factor_df_with_ret[[\"date\", \"instrument\", \"close\", \"ret\", \"factor\", \"daily_ret_1\"]]\n # 标准化,去极值处理\n if self.is_standardlize and not self.is_winsorize:\n base_factor_df = base_factor_df.groupby(\"date\").apply(lambda x: _standardlize(x)).reset_index(drop=True)\n elif self.is_winsorize and not self.is_standardlize:\n base_factor_df = base_factor_df.groupby(\"date\").apply(lambda x: _winsorize(x)).reset_index(drop=True)\n elif self.is_winsorize and self.is_standardlize:\n base_factor_df = base_factor_df.groupby(\"date\").apply(lambda x: _standardlize(_winsorize(x))).reset_index(drop=True)\n # 对数据根据时间进行过滤\n base_factor_df = base_factor_df[(base_factor_df['date']>self.start_date) & ((base_factor_df['date']<self.end_date))]\n # 对应用户抽取的列名\n# print(\"base_factor_df1=\",self.start_date,self.end_date,base_factor_df)\n base_factor_df[factor_name] = base_factor_df[\"factor\"]\n td = D.trading_days(start_date=base_factor_df.date.min().strftime('%Y-%m-%d'))\n rebalance_days = td[::self.rabalance_period] # 调仓期\n rebalance_days_df = pd.DataFrame({'date': rebalance_days['date'], 'ix': range(len(rebalance_days))})\n rebalance_days_df.index = range(len(rebalance_days_df))\n merge_df = pd.merge(base_factor_df, rebalance_days_df, on='date', how='inner')\n\n # 将因子名或因子表达式抽取出来做展示处理\n \n return merge_df, base_factor_df, factor_name\n\n def ic_processing(self, merge_df, factor_name):\n start_time = time.time()\n \n def _cal_IC(df, method=\"Rank_IC\"):\n \"\"\"计算IC系数\"\"\"\n from scipy.stats import pearsonr, spearmanr\n\n df = df.dropna()\n if df.shape[0] == 0:\n return np.nan\n if method == \"Rank_IC\":\n return spearmanr(df[\"factor\"], df[\"ret\"])[0]\n if method == \"IC\":\n return pearsonr(df[\"factor\"], df[\"ret\"])[0]\n ic = merge_df.groupby(\"date\").apply(_cal_IC, method=self.ic_method)\n # ic相关指标\n ic_mean = np.round(ic.mean(), 4)\n ic_std = np.round(ic.std(), 4)\n ic_ir = np.round(ic_mean / ic_std, 4)\n positive_ic_cnt = len(ic[ic > 0])\n negative_ic_cnt = len(ic[ic < 0])\n ic_skew = np.round(ic.skew(), 4)\n ic_kurt = np.round(ic.kurt(), 4)\n # IC指标展示\n results = {\n \"stats\": {\n \"ic_mean\": ic_mean,\n \"ic_std\": ic_std,\n \"ic_ir\": ic_ir,\n \"positive_ic_cnt\": positive_ic_cnt,\n \"negative_ic_cnt\": negative_ic_cnt,\n \"ic_skew\": ic_skew,\n \"ic_kurt\": ic_kurt,\n },\n \"title\": f\"{factor_name}: IC分析\",\n }\n ic.name = \"ic\"\n ic_df = ic.to_frame()\n ic_df[\"ic_cumsum\"] = ic_df[\"ic\"].cumsum()\n \n return ic_df, results\n\n def ols_stats_processing(self, merge_df, factor_name):\n start_time = time.time()\n \n def _get_model_stats(X, y):\n from pyfinance import ols\n model = ols.OLS(y=y, x=X)\n return [model.beta, model.tstat_beta, model.pvalue_beta, model.se_beta]\n ols_stats = merge_df.dropna().groupby(\"date\").apply(lambda df: _get_model_stats(df[[\"factor\"]], df[\"ret\"]))\n ols_stats_df = pd.DataFrame(ols_stats)\n ols_stats_df.rename(columns={0: \"ols_result\"}, inplace=True)\n ols_stats_df[\"beta\"] = ols_stats_df[\"ols_result\"].apply(lambda x: x[0])\n ols_stats_df[\"tstat_beta\"] = ols_stats_df[\"ols_result\"].apply(lambda x: x[1])\n ols_stats_df[\"pvalue_beta\"] = ols_stats_df[\"ols_result\"].apply(lambda x: x[2])\n ols_stats_df[\"se_beta\"] = ols_stats_df[\"ols_result\"].apply(lambda x: x[3])\n ols_stats_df = ols_stats_df[[\"beta\", \"tstat_beta\", \"pvalue_beta\", \"se_beta\"]]\n\n roll_beta_period = 12\n ols_stats_df[\"cum_beta\"] = ols_stats_df[\"beta\"].cumsum()\n ols_stats_df[\"roll_beta\"] = ols_stats_df[\"beta\"].rolling(roll_beta_period).mean()\n\n # 因子收益率数据加工\n ols_stats_df[\"abs_t_value\"] = ols_stats_df[\"tstat_beta\"].abs()\n # 相应指标\n beta_mean = np.round(ols_stats_df[\"beta\"].mean(), 4)\n beta_std = np.round(ols_stats_df[\"beta\"].std(), 4)\n positive_beta_ratio = np.round(len(ols_stats_df[\"beta\"][ols_stats_df[\"beta\"] > 0]) / len(ols_stats_df), 4) * 100\n abs_t_mean = np.round(ols_stats_df[\"abs_t_value\"].mean(), 4)\n abs_t_value_over_two_ratio = np.round(len(ols_stats_df[\"abs_t_value\"][ols_stats_df[\"abs_t_value\"] > 2]) / len(ols_stats_df[\"abs_t_value\"]), 4)\n p_value_less_ratio = np.round(len(ols_stats_df[\"pvalue_beta\"][ols_stats_df[\"pvalue_beta\"] < 0.05]) / len(ols_stats_df[\"pvalue_beta\"]), 4)\n\n results = {\n \"stats\": {\n \"beta_mean\": beta_mean,\n \"beta_std\": beta_std,\n \"positive_beta_ratio\": positive_beta_ratio,\n \"abs_t_mean\": abs_t_mean,\n \"abs_t_value_over_two_ratio\": abs_t_value_over_two_ratio,\n \"p_value_less_ratio\": p_value_less_ratio,\n },\n \"title\": f\"{factor_name}: 因子收益率分析\",\n }\n \n return ols_stats_df, results\n\n def group_processing(self, merge_df, base_factor_df, factor_name):\n start_time = time.time()\n \n\n def _fill_ix_na(df):\n df['rebalance_index'] = df['ix'].fillna(method='ffill')\n return df\n\n def _unify_factor(tmp):\n \"\"\"因子以调仓期首日因子为准\"\"\"\n tmp['factor'] = list(tmp['factor'])[0]\n return tmp\n\n def _cut_box(df, quantile_num=5):\n if df.factor.isnull().sum() == len(df): # 因子值全是nan的话\n df[\"factor_group\"] = [np.nan] * len(df)\n else:\n labels = [str(i) for i in range(quantile_num)]\n df[\"factor_group\"] = pd.qcut(df[\"factor\"], quantile_num, labels=labels) # 升序排序,分成5组\n return df\n\n # 计算绩效指标\n def _get_stats(results, col_name):\n import empyrical\n return_ratio = np.round(empyrical.cum_returns_final(results[col_name]), 4)\n annual_return_ratio = np.round(empyrical.annual_return(results[col_name]), 4)\n sharp_ratio = np.round(empyrical.sharpe_ratio(results[col_name], 0.035/252), 4)\n return_volatility = np.round(empyrical.annual_volatility(results[col_name]), 4)\n max_drawdown = np.round(empyrical.max_drawdown(results[col_name]), 4)\n res = {'收益率': [return_ratio]}\n date_dict = {1: \"1日\", 5: \"1周\", 22: \"1月\"}\n for n in [1, 5, 22]:\n res['近{}收益率'.format(date_dict[n])] = np.round(results[col_name.replace('ret', 'pv')][-1] / results[col_name.replace('ret', 'pv')][-(n+1)] -1, 4)\n res.update({\n '年化收益率': [annual_return_ratio],\n '夏普比率': [sharp_ratio],\n '收益波动率': [return_volatility],\n '最大回撤': [max_drawdown]})\n return pd.DataFrame(res)\n\n merge_df2 = pd.merge(base_factor_df[['date', 'instrument', 'factor', 'daily_ret_1']],\n merge_df[['date', 'instrument', 'ix']], how='left', on=['date', 'instrument'])\n\n merge_df2 = merge_df2.groupby('instrument').apply(_fill_ix_na)\n unify_factor_df = merge_df2.groupby(['rebalance_index', 'instrument']).apply(_unify_factor)\n group_df = unify_factor_df.groupby(\"date\").apply(_cut_box, quantile_num=self.quantile_num)\n # 计算每组每天的收益率\n result = group_df[['date', 'factor_group', 'daily_ret_1', 'rebalance_index', 'ix']].groupby(['factor_group', 'date']).mean().reset_index()\n \n \n # 调仓日的收益率需要扣除交易成本\n result['daily_ret_1'] -= (self.buy_commission_rate + self.sell_commission_rate) * np.where(result['ix'].isna(), 0, 1)\n result_table = result.pivot(values=\"daily_ret_1\", columns=\"factor_group\", index=\"date\")\n \n result_table.rename(columns={i: 'top%s_ret' % i for i in result_table.columns}, inplace=True)\n \n small_quantile_name = result_table.columns.min()\n big_quantile_name = result_table.columns.max()\n long_short_name = 'LS_ret'\n result_table[\"LS_ret\"] = (result_table[small_quantile_name] - result_table[big_quantile_name])/2\n # 移除na值, 防止收益计算为Na\n result_table.dropna(inplace=True)\n \n for i in result_table.columns:\n col_name = i.split(\"_\")[0] + \"_\" + \"pv\"\n result_table[col_name] = (1 + result_table[i]).cumprod()\n \n small_quantile_perf = _get_stats(result_table, small_quantile_name)\n big_quantile_perf = _get_stats(result_table, big_quantile_name)\n long_short_perf = _get_stats(result_table,long_short_name )\n df = pd.concat([small_quantile_perf, big_quantile_perf,long_short_perf])\n df.index = [small_quantile_name, big_quantile_name,long_short_name]\n \n results = {\n \"stats\": df.T.to_dict(),\n \"title\": f\"{factor_name}: 因子绩效分析\",\n }\n \n \n return result_table, results\n\n def process(self, continus_contract_df, factors_name):\n factor_data = []\n performance_data = []\n # 进行因子计算\n for factor_name in factors_name:\n if factor_name.startswith(\"_\"):\n continue\n merge_df, base_factor_df, factor_name = self.data_processing(continus_contract_df, factor_name)\n ic_data = self.ic_processing(merge_df, factor_name)\n ols_data = self.ols_stats_processing(merge_df, factor_name)\n group_data = self.group_processing(merge_df, base_factor_df, factor_name)\n # 保存因子相关信息\n options_data = {\n \"start_date\": self.start_date,\n \"end_date\": self.end_date,\n \"rabalance_period\": self.rabalance_period,\n \"buy_commission_rate\": self.buy_commission_rate,\n \"sell_commission_rate\": self.sell_commission_rate,\n \"ic_method\": self.ic_method,\n \"quantile_num\": self.quantile_num,\n }\n result = {\n \"summary\": {\"IC\": ic_data[1], \"FactorReturns\": ols_data[1], \"QuantileReturns\": group_data[1]},\n \"data\": {\"IC\": ic_data[0], \"FactorReturns\": ols_data[0], \"QuantileReturns\": group_data[0]},\n \"options\": options_data,\n }\n factor_data.append(base_factor_df)\n performance_data.append(result)\n\n return factor_data, performance_data\n \ndef bigquant_run(input_1, input_2, input_3, rabalance_period, buy_commission_rate, sell_commission_rate, \n ic_method, quantile_num, is_standardlize, is_winsorize):\n \n start_date, end_date, instruments = input_1.read()[\"start_date\"], input_1.read()[\"end_date\"], input_1.read()[\"instruments\"]\n df_factor = input_2.read()\n factors_name = input_3.read()\n md = DataSource(\"bar1d_CN_FUTURE\").read(instruments=instruments, start_date=start_date, end_date=end_date, fields=[\"close\"])\n \n continus_contract_df = df_factor.merge(md, on=[\"instrument\", \"date\"], how=\"left\")\n\n \n fp = FuturesPerformance( start_date, end_date, rabalance_period, buy_commission_rate, sell_commission_rate, ic_method, quantile_num, is_standardlize, is_winsorize)\n data_1, data_2 = fp.process(continus_contract_df, factors_name)\n res = {}\n for factor in factors_name:\n fact_explain = factor.split(\"=\")\n if len(fact_explain) > 1:\n factor_expr = fact_explain[1].strip()\n factor_name = fact_explain[0].strip()\n res[factor_name] = {}\n options = data_2[0][\"options\"]\n summary = data_2[0][\"summary\"]\n metrics = {}\n metrics[\"IC均值\"] = summary[\"IC\"][\"stats\"][\"ic_mean\"]\n metrics[\"IC_IR\"] = summary[\"IC\"][\"stats\"][\"ic_ir\"]\n metrics[\"近1日收益率\"] = summary[\"QuantileReturns\"][\"stats\"][\"top0_ret\"][\"近1日收益率\"]\n metrics[\"近1周收益率\"] = summary[\"QuantileReturns\"][\"stats\"][\"top0_ret\"][\"近1周收益率\"]\n metrics[\"近1月收益率\"] = summary[\"QuantileReturns\"][\"stats\"][\"top0_ret\"][\"近1月收益率\"]\n datasource = data_1[0][[\"date\", \"instrument\", factor_name]]\n column_name = factor_name\n expr = factor_expr if len(fact_explain) > 1 else \"\"\n for info in [{\"options\": options}, {\"metrics\": metrics}, {\"datasource\": datasource}, {\"column_name\": column_name}, {\"expr\": expr}]:\n res[factor_name].update(info)\n \n data_1 = DataSource.write_pickle(res)\n data_2 = DataSource.write_pickle(data_2)\n return Outputs(data_1=data_1, data_2=data_2, data_3=None)","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n from jinja2 import Template\n from biglearning.module2.common.utils import display_html\n \n class RenderHtml:\n ic_stats_template = \"\"\"\n <div style=\"width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;\"><h2>{{ title }}</h2></div>\n <div class='kpicontainer'>\n <ul class='kpi'>\n <li><span class='title'>IC均值</span><span class='value'>{{ stats.ic_mean }}</span></li>\n <li><span class='title'>IC标准差</span><span class='value'>{{ stats.ic_std }}</span></li>\n <li><span class='title'>ICIR</span><span class='value'>{{ stats.ic_ir }}</span></li>\n <li><span class='title'>IC正值次数</span><span class='value'>{{ stats.positive_ic_cnt }}次</span></li>\n <li><span class='title'>IC负值次数</span><span class='value'>{{ stats.negative_ic_cnt }}次</span></li>\n <li><span class='title'>IC偏度</span><span class='value'>{{ stats.ic_skew }}</span></li>\n <li><span class='title'>IC峰度</span><span class='value'>{{ stats.ic_kurt }}</span></li>\n </ul>\n </div>\n \"\"\"\n ols_stats_template = \"\"\"\n <div style=\"width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;\"><h2>{{ title }}</h2></div>\n <div class='kpicontainer'>\n <ul class='kpi'>\n <li><span class='title'>因子收益均值</span><span class='value'>{{ stats.beta_mean }}</span></li>\n <li><span class='title'>因子收益标准差</span><span class='value'>{{ stats.beta_std }}</span></li>\n <li><span class='title'>因子收益为正比率</span><span class='value'>{{ stats.positive_beta_ratio }}%</span></li>\n <li><span class='title'>t值绝对值的均值</span><span class='value'>{{ stats.abs_t_mean }}</span></li>\n <li><span class='title'>t值绝对值大于2的比率</span><span class='value'>{{ stats.abs_t_value_over_two_ratio }}</span></li>\n <li><span class='title'>因子收益t检验p值小于0.05的比率</span><span class='value'>{{ stats.p_value_less_ratio }}</span></li>\n </ul>\n </div>\n \"\"\"\n group_stats_template = \"\"\"\n <div style=\"width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;\"><h2>{{ title }}</h2></div>\n <div class='kpicontainer'>\n <ul class='kpi'>\n <li><span class='title'>&nbsp;</span>\n {% for k in stats%}\n <span class='value'>{{ k }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>收益率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].收益率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>近1日收益率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].近1日收益率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>近1周收益率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].近1周收益率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>近1月收益率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].近1月收益率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>年化收益率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].年化收益率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>夏普比率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].夏普比率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>收益波动率</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].收益波动率 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n <li><span class='title'>最大回撤</span>\n {% for k in stats%}\n <span class='value'>{{ (stats[k].最大回撤 | string)[0:10] }}</span>\n {% endfor %}\n </li>\n </ul>\n </div>\n \"\"\"\n\n def __init__(self, ic_data, ic_summary, factor_returns_data, factor_returns_summary, quantile_returns_data, quantile_returns_summary):\n self.ic_df = ic_data\n self.ic_results = ic_summary\n self.ols_stats_df = factor_returns_data\n self.ols_stats_results = factor_returns_summary\n self.group_df = quantile_returns_data\n self.group_df_results = quantile_returns_summary\n\n def render_results(self, stats_template, results):\n \"\"\" 展示模板信息 \"\"\"\n\n def render(stats_template, results):\n html = Template(stats_template).render(stats=results[\"stats\"], title=results[\"title\"])\n display_html(html)\n\n render(stats_template, results)\n\n def show_ic(self):\n self.render_results(self.ic_stats_template, self.ic_results)\n T.plot(\n self.ic_df,\n title=\"IC分析\",\n panes=[[\"ic\", \"40%\"], [\"ic_cumsum\", \"20%\"]],\n # height=500,设置高度为500\n options={\n \"chart\": {\"height\": 500},\n # 设置颜色\n \"series\": [\n {\n \"name\": \"ic\",\n \"color\": \"#8085e8\",\n \"type\": \"column\",\n \"yAxis\": 0,\n },\n {\n \"name\": \"ic_cumsum\",\n \"color\": \"#8d4653\",\n \"type\": \"spline\",\n \"yAxis\": 0,\n },\n ],\n },\n )\n\n def show_ols(self):\n self.render_results(self.ols_stats_template, self.ols_stats_results)\n T.plot(\n self.ols_stats_df[[\"beta\", \"cum_beta\", \"roll_beta\"]],\n title=\"因子收益率\",\n # high、low显示在第一栏,高度40%,open、close显示在第二栏,其他的在最后一栏\n panes=[[\"beta\", \"cum_beta\", \"40%\"], [\"roll_beta\", \"20%\"]],\n # height=500,设置高度为500\n options={\n \"chart\": {\"height\": 500},\n # 设置颜色\n \"series\": [\n {\n \"name\": \"beta\",\n \"color\": \"#8085e8\",\n \"type\": \"column\",\n \"yAxis\": 0,\n },\n {\n \"name\": \"cum_beta\",\n \"color\": \"#8d4653\",\n \"type\": \"column\",\n \"yAxis\": 0,\n },\n {\n \"name\": \"roll_beta\",\n \"color\": \"#91e8e1\",\n \"type\": \"spline\",\n \"yAxis\": 1,\n },\n ],\n },\n )\n\n def show_group(self):\n self.render_results(self.group_stats_template, self.group_df_results)\n T.plot(self.group_df[[i for i in self.group_df.columns if \"_pv\" in i]])\n \n def show(self):\n self.show_ic()\n self.show_ols()\n self.show_group()\n \n # 读取 IC,FactorReturns,QuantileReturns用作展示\n performance_data = outputs.data_2.read()\n for data in performance_data:\n ic_data = data[\"data\"][\"IC\"]\n factor_returns_data = data[\"data\"][\"FactorReturns\"]\n quantile_returns_data = data[\"data\"][\"QuantileReturns\"]\n ic_summary = data[\"summary\"][\"IC\"]\n factor_returns_summary = data[\"summary\"][\"FactorReturns\"]\n quantile_returns_summary = data[\"summary\"][\"QuantileReturns\"]\n renderhtml = RenderHtml(ic_data, ic_summary, factor_returns_data, factor_returns_summary, quantile_returns_data, quantile_returns_summary)\n renderhtml.show()\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"input_1, input_2, input_3","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{\n 'rabalance_period': 22,\n 'buy_commission_rate': 0.0005,\n 'sell_commission_rate': 0.0005,\n 'ic_method': 'Rank_IC',\n 'quantile_num': 5,\n 'is_standardlize': True,\n 'is_winsorize': True\n}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"data_1, data_2","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-143"},{"name":"input_2","node_id":"-143"},{"name":"input_3","node_id":"-143"}],"output_ports":[{"name":"data_1","node_id":"-143"},{"name":"data_2","node_id":"-143"},{"name":"data_3","node_id":"-143"}],"cacheable":false,"seq_num":6,"comment":"自定义因子分析模块","comment_collapsed":false},{"node_id":"-460","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2020-01-02","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-10-12","type":"Literal","bound_global_parameter":"交易日期"},{"name":"market","value":"CN_FUTURE","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"A8888.DCE\nAG8888.SHF\nAL8888.SHF\nAU8888.SHF\nB8888.DCE\nBB8888.DCE\nBU8888.SHF\n# C88.DCE\n# CF88.CZC\n# CS88.DCE\n# CU88.SHF\n# FB88.DCE\n# FG88.CZC\n# FU88.SHF\n# HC88.SHF\n# I88.DCE\n# J88.DCE\n# JD88.DCE\n# JM88.DCE\n# JR88.CZC\n# L88.DCE\n# LR88.CZC\n# M88.DCE\n# MA88.CZC\n# OI88.CZC\n# P88.DCE\n# PB88.SHF\n# PM88.CZC\n# PP88.DCE\n# RB88.SHF\n# RM88.CZC \n# RU88.SHF\n# SF88.CZC\n# SM88.CZC\n# SR88.CZC\n# TA88.CZC\n# TF88.CFX\n# V88.DCE\n# Y88.DCE\n# ZN88.SHF\n# NI88.SHF\n# SN88.SHF\n# ZC88.CZC\n# CY88.CZC\n# AP88.CZC\n# SC88.INE\n# SP88.SHF\n# EG88.DCE\n# EB88.DCE\n# SA88.CZC\n# PG88.DCE\n# LU88.INE\n# PF88.CZC","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-460"}],"output_ports":[{"name":"data","node_id":"-460"}],"cacheable":true,"seq_num":7,"comment":"","comment_collapsed":true},{"node_id":"-47","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"factor\n\n","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-47"}],"output_ports":[{"name":"data","node_id":"-47"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-331' Position='35,-85,200,200'/><node_position Node='-726' Position='-27,75,200,200'/><node_position Node='-34' Position='-15,341,200,200'/><node_position Node='-143' Position='-16,211,200,200'/><node_position Node='-460' Position='-336,-105,200,200'/><node_position Node='-47' Position='305,116,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [9]:
    # 本代码由可视化策略环境自动生成 2021年10月18日 13:34
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    from datetime import datetime
    import time
    import bigexpr
    
     
    
    class FuturesPerformance:
        def __init__(self,start_date=None,end_date=None,rabalance_period=22,buy_commission_rate=0.0005,sell_commission_rate=0.0005,ic_method="Rank_IC",quantile_num=5,is_standardlize=True,is_winsorize=True):
     
      
            self.start_date = start_date
            self.end_date = end_date
            self.rabalance_period = rabalance_period  # 调仓天数
            self.buy_commission_rate = buy_commission_rate  # 买入佣金(百分比)
            self.sell_commission_rate = sell_commission_rate  # 卖出佣金(百分比)
            self.ic_method = ic_method
            self.quantile_num = quantile_num
            self.is_standardlize = is_standardlize  # 是否标准化
            self.is_winsorize = is_winsorize  # 是否去极值
    
        def data_processing(self, continus_contract_df, factor_name):
            # 表达式抽取
            start_time = time.time()
    
    
            def _handle_data(df, factor_name, price_type):
                # 计算当期因子和未来一段时间收益率
                # df["factor"] = df["close"] / df["close"].shift(44) - 1  # 构建因子
                df["factor"] = df[factor_name]
    
                # 持有期收益率
                df["ret"] = df[price_type].shift(-1 * self.rabalance_period) / df[price_type] - 1
                df['ret'] = df.ret.shift(-1)  # 下一期的收益率
                df['daily_ret_1'] = df['close'].pct_change().shift(-1)  # 次日收益率
                return df
    
            # 极值数据处理
            def _winsorize(df):
                df = df.copy()
                factor_columns = ["factor"]
                for factor in factor_columns:
                    mean = df[factor].mean()
                    sigma = df[factor].std()
                    df[factor] = df[factor].clip(mean - 3 * sigma, mean + 3 * sigma)
                return df
    
            # 标准数据处理
            def _standardlize(df):
                df = df.copy()
                factor_columns = ["factor"]
                for factor in factor_columns:
                    mean = df[factor].mean()
                    sigma = df[factor].std()
                    df[factor] = (df[factor] - mean) / sigma
                return df
     
            factor_df_with_ret = continus_contract_df.groupby("instrument").apply(_handle_data, factor_name=factor_name, price_type="close")
     
            base_factor_df = factor_df_with_ret[["date", "instrument", "close", "ret", "factor", "daily_ret_1"]]
            # 标准化,去极值处理
            if self.is_standardlize and not self.is_winsorize:
                base_factor_df = base_factor_df.groupby("date").apply(lambda x: _standardlize(x)).reset_index(drop=True)
            elif self.is_winsorize and not self.is_standardlize:
                base_factor_df = base_factor_df.groupby("date").apply(lambda x: _winsorize(x)).reset_index(drop=True)
            elif self.is_winsorize and self.is_standardlize:
                base_factor_df = base_factor_df.groupby("date").apply(lambda x: _standardlize(_winsorize(x))).reset_index(drop=True)
            # 对数据根据时间进行过滤
            base_factor_df = base_factor_df[(base_factor_df['date']>self.start_date) & ((base_factor_df['date']<self.end_date))]
            # 对应用户抽取的列名
    #         print("base_factor_df1=",self.start_date,self.end_date,base_factor_df)
            base_factor_df[factor_name] = base_factor_df["factor"]
            td = D.trading_days(start_date=base_factor_df.date.min().strftime('%Y-%m-%d'))
            rebalance_days = td[::self.rabalance_period]  # 调仓期
            rebalance_days_df = pd.DataFrame({'date': rebalance_days['date'], 'ix': range(len(rebalance_days))})
            rebalance_days_df.index = range(len(rebalance_days_df))
            merge_df = pd.merge(base_factor_df, rebalance_days_df, on='date', how='inner')
    
            # 将因子名或因子表达式抽取出来做展示处理
            
            return merge_df, base_factor_df, factor_name
    
        def ic_processing(self, merge_df, factor_name):
            start_time = time.time()
            
            def _cal_IC(df, method="Rank_IC"):
                """计算IC系数"""
                from scipy.stats import pearsonr, spearmanr
    
                df = df.dropna()
                if df.shape[0] == 0:
                    return np.nan
                if method == "Rank_IC":
                    return spearmanr(df["factor"], df["ret"])[0]
                if method == "IC":
                    return pearsonr(df["factor"], df["ret"])[0]
            ic = merge_df.groupby("date").apply(_cal_IC, method=self.ic_method)
            # ic相关指标
            ic_mean = np.round(ic.mean(), 4)
            ic_std = np.round(ic.std(), 4)
            ic_ir = np.round(ic_mean / ic_std, 4)
            positive_ic_cnt = len(ic[ic > 0])
            negative_ic_cnt = len(ic[ic < 0])
            ic_skew = np.round(ic.skew(), 4)
            ic_kurt = np.round(ic.kurt(), 4)
            # IC指标展示
            results = {
                "stats": {
                    "ic_mean": ic_mean,
                    "ic_std": ic_std,
                    "ic_ir": ic_ir,
                    "positive_ic_cnt": positive_ic_cnt,
                    "negative_ic_cnt": negative_ic_cnt,
                    "ic_skew": ic_skew,
                    "ic_kurt": ic_kurt,
                },
                "title": f"{factor_name}: IC分析",
            }
            ic.name = "ic"
            ic_df = ic.to_frame()
            ic_df["ic_cumsum"] = ic_df["ic"].cumsum()
           
            return ic_df, results
    
        def ols_stats_processing(self, merge_df, factor_name):
            start_time = time.time()
            
            def _get_model_stats(X, y):
                from pyfinance import ols
                model = ols.OLS(y=y, x=X)
                return [model.beta, model.tstat_beta, model.pvalue_beta, model.se_beta]
            ols_stats = merge_df.dropna().groupby("date").apply(lambda df: _get_model_stats(df[["factor"]], df["ret"]))
            ols_stats_df = pd.DataFrame(ols_stats)
            ols_stats_df.rename(columns={0: "ols_result"}, inplace=True)
            ols_stats_df["beta"] = ols_stats_df["ols_result"].apply(lambda x: x[0])
            ols_stats_df["tstat_beta"] = ols_stats_df["ols_result"].apply(lambda x: x[1])
            ols_stats_df["pvalue_beta"] = ols_stats_df["ols_result"].apply(lambda x: x[2])
            ols_stats_df["se_beta"] = ols_stats_df["ols_result"].apply(lambda x: x[3])
            ols_stats_df = ols_stats_df[["beta", "tstat_beta", "pvalue_beta", "se_beta"]]
    
            roll_beta_period = 12
            ols_stats_df["cum_beta"] = ols_stats_df["beta"].cumsum()
            ols_stats_df["roll_beta"] = ols_stats_df["beta"].rolling(roll_beta_period).mean()
    
            # 因子收益率数据加工
            ols_stats_df["abs_t_value"] = ols_stats_df["tstat_beta"].abs()
            # 相应指标
            beta_mean = np.round(ols_stats_df["beta"].mean(), 4)
            beta_std = np.round(ols_stats_df["beta"].std(), 4)
            positive_beta_ratio = np.round(len(ols_stats_df["beta"][ols_stats_df["beta"] > 0]) / len(ols_stats_df), 4) * 100
            abs_t_mean = np.round(ols_stats_df["abs_t_value"].mean(), 4)
            abs_t_value_over_two_ratio = np.round(len(ols_stats_df["abs_t_value"][ols_stats_df["abs_t_value"] > 2]) / len(ols_stats_df["abs_t_value"]), 4)
            p_value_less_ratio = np.round(len(ols_stats_df["pvalue_beta"][ols_stats_df["pvalue_beta"] < 0.05]) / len(ols_stats_df["pvalue_beta"]), 4)
    
            results = {
                "stats": {
                    "beta_mean": beta_mean,
                    "beta_std": beta_std,
                    "positive_beta_ratio": positive_beta_ratio,
                    "abs_t_mean": abs_t_mean,
                    "abs_t_value_over_two_ratio": abs_t_value_over_two_ratio,
                    "p_value_less_ratio": p_value_less_ratio,
                },
                "title": f"{factor_name}: 因子收益率分析",
            }
            
            return ols_stats_df, results
    
        def group_processing(self, merge_df, base_factor_df, factor_name):
            start_time = time.time()
            
    
            def _fill_ix_na(df):
                df['rebalance_index'] = df['ix'].fillna(method='ffill')
                return df
    
            def _unify_factor(tmp):
                """因子以调仓期首日因子为准"""
                tmp['factor'] = list(tmp['factor'])[0]
                return tmp
    
            def _cut_box(df, quantile_num=5):
                if df.factor.isnull().sum() == len(df):  # 因子值全是nan的话
                    df["factor_group"] = [np.nan] * len(df)
                else:
                    labels = [str(i) for i in range(quantile_num)]
                    df["factor_group"] = pd.qcut(df["factor"], quantile_num, labels=labels)  # 升序排序,分成5组
                return df
    
            # 计算绩效指标
            def _get_stats(results, col_name):
                import empyrical
                return_ratio = np.round(empyrical.cum_returns_final(results[col_name]), 4)
                annual_return_ratio = np.round(empyrical.annual_return(results[col_name]), 4)
                sharp_ratio = np.round(empyrical.sharpe_ratio(results[col_name], 0.035/252), 4)
                return_volatility = np.round(empyrical.annual_volatility(results[col_name]), 4)
                max_drawdown = np.round(empyrical.max_drawdown(results[col_name]), 4)
                res = {'收益率': [return_ratio]}
                date_dict = {1: "1日", 5: "1周", 22: "1月"}
                for n in [1, 5, 22]:
                    res['近{}收益率'.format(date_dict[n])] = np.round(results[col_name.replace('ret', 'pv')][-1] / results[col_name.replace('ret', 'pv')][-(n+1)] -1, 4)
                res.update({
                '年化收益率': [annual_return_ratio],
                '夏普比率': [sharp_ratio],
                '收益波动率': [return_volatility],
                '最大回撤': [max_drawdown]})
                return pd.DataFrame(res)
    
            merge_df2 = pd.merge(base_factor_df[['date', 'instrument', 'factor', 'daily_ret_1']],
                                 merge_df[['date', 'instrument', 'ix']], how='left', on=['date', 'instrument'])
    
            merge_df2 = merge_df2.groupby('instrument').apply(_fill_ix_na)
            unify_factor_df = merge_df2.groupby(['rebalance_index', 'instrument']).apply(_unify_factor)
            group_df = unify_factor_df.groupby("date").apply(_cut_box, quantile_num=self.quantile_num)
            # 计算每组每天的收益率
            result = group_df[['date', 'factor_group', 'daily_ret_1', 'rebalance_index', 'ix']].groupby(['factor_group', 'date']).mean().reset_index()
            
            
            # 调仓日的收益率需要扣除交易成本
            result['daily_ret_1'] -= (self.buy_commission_rate + self.sell_commission_rate) * np.where(result['ix'].isna(), 0, 1)
            result_table = result.pivot(values="daily_ret_1", columns="factor_group", index="date")
            
            result_table.rename(columns={i: 'top%s_ret' % i for i in result_table.columns}, inplace=True)
           
            small_quantile_name = result_table.columns.min()
            big_quantile_name = result_table.columns.max()
            long_short_name = 'LS_ret'
            result_table["LS_ret"] = (result_table[small_quantile_name] - result_table[big_quantile_name])/2
            # 移除na值, 防止收益计算为Na
            result_table.dropna(inplace=True)
           
            for i in result_table.columns:
                col_name = i.split("_")[0] + "_" + "pv"
                result_table[col_name] = (1 + result_table[i]).cumprod()
            
            small_quantile_perf = _get_stats(result_table, small_quantile_name)
            big_quantile_perf = _get_stats(result_table, big_quantile_name)
            long_short_perf = _get_stats(result_table,long_short_name )
            df = pd.concat([small_quantile_perf, big_quantile_perf,long_short_perf])
            df.index = [small_quantile_name, big_quantile_name,long_short_name]
     
            results = {
                "stats": df.T.to_dict(),
                "title": f"{factor_name}: 因子绩效分析",
            }
     
            
            return result_table, results
    
        def process(self, continus_contract_df, factors_name):
            factor_data = []
            performance_data = []
            # 进行因子计算
            for factor_name in factors_name:
                if factor_name.startswith("_"):
                    continue
                merge_df, base_factor_df, factor_name = self.data_processing(continus_contract_df, factor_name)
                ic_data = self.ic_processing(merge_df, factor_name)
                ols_data = self.ols_stats_processing(merge_df, factor_name)
                group_data = self.group_processing(merge_df, base_factor_df, factor_name)
                # 保存因子相关信息
                options_data = {
                    "start_date": self.start_date,
                    "end_date": self.end_date,
                    "rabalance_period": self.rabalance_period,
                    "buy_commission_rate": self.buy_commission_rate,
                    "sell_commission_rate": self.sell_commission_rate,
                    "ic_method": self.ic_method,
                    "quantile_num": self.quantile_num,
                }
                result = {
                    "summary": {"IC": ic_data[1], "FactorReturns": ols_data[1], "QuantileReturns": group_data[1]},
                    "data": {"IC": ic_data[0], "FactorReturns": ols_data[0], "QuantileReturns": group_data[0]},
                    "options": options_data,
                }
                factor_data.append(base_factor_df)
                performance_data.append(result)
    
            return factor_data, performance_data
            
    def m6_run_bigquant_run(input_1, input_2, input_3, rabalance_period, buy_commission_rate, sell_commission_rate, 
                     ic_method, quantile_num, is_standardlize, is_winsorize):
            
        start_date, end_date, instruments = input_1.read()["start_date"], input_1.read()["end_date"], input_1.read()["instruments"]
        df_factor = input_2.read()
        factors_name = input_3.read()
        md = DataSource("bar1d_CN_FUTURE").read(instruments=instruments, start_date=start_date, end_date=end_date, fields=["close"])
     
        continus_contract_df = df_factor.merge(md, on=["instrument", "date"], how="left")
    
        
        fp = FuturesPerformance( start_date, end_date, rabalance_period, buy_commission_rate, sell_commission_rate, ic_method, quantile_num, is_standardlize, is_winsorize)
        data_1, data_2 = fp.process(continus_contract_df, factors_name)
        res = {}
        for factor in factors_name:
            fact_explain = factor.split("=")
            if len(fact_explain) > 1:
                factor_expr = fact_explain[1].strip()
            factor_name = fact_explain[0].strip()
            res[factor_name] = {}
            options = data_2[0]["options"]
            summary = data_2[0]["summary"]
            metrics = {}
            metrics["IC均值"] = summary["IC"]["stats"]["ic_mean"]
            metrics["IC_IR"] = summary["IC"]["stats"]["ic_ir"]
            metrics["近1日收益率"] = summary["QuantileReturns"]["stats"]["top0_ret"]["近1日收益率"]
            metrics["近1周收益率"] = summary["QuantileReturns"]["stats"]["top0_ret"]["近1周收益率"]
            metrics["近1月收益率"] = summary["QuantileReturns"]["stats"]["top0_ret"]["近1月收益率"]
            datasource = data_1[0][["date", "instrument", factor_name]]
            column_name = factor_name
            expr = factor_expr if len(fact_explain) > 1 else ""
            for info in [{"options": options}, {"metrics": metrics}, {"datasource": datasource}, {"column_name": column_name}, {"expr": expr}]:
                res[factor_name].update(info)
        
        data_1 = DataSource.write_pickle(res)
        data_2 = DataSource.write_pickle(data_2)
        return Outputs(data_1=data_1, data_2=data_2, data_3=None)
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m6_post_run_bigquant_run(outputs):
        from jinja2 import Template
        from biglearning.module2.common.utils import display_html
        
        class RenderHtml:
            ic_stats_template = """
            <div style="width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;"><h2>{{ title }}</h2></div>
            <div class='kpicontainer'>
                <ul class='kpi'>
                    <li><span class='title'>IC均值</span><span class='value'>{{ stats.ic_mean }}</span></li>
                    <li><span class='title'>IC标准差</span><span class='value'>{{ stats.ic_std }}</span></li>
                    <li><span class='title'>ICIR</span><span class='value'>{{ stats.ic_ir }}</span></li>
                    <li><span class='title'>IC正值次数</span><span class='value'>{{ stats.positive_ic_cnt }}次</span></li>
                    <li><span class='title'>IC负值次数</span><span class='value'>{{ stats.negative_ic_cnt }}次</span></li>
                    <li><span class='title'>IC偏度</span><span class='value'>{{ stats.ic_skew }}</span></li>
                    <li><span class='title'>IC峰度</span><span class='value'>{{ stats.ic_kurt }}</span></li>
                </ul>
            </div>
            """
            ols_stats_template = """
            <div style="width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;"><h2>{{ title }}</h2></div>
            <div class='kpicontainer'>
                <ul class='kpi'>
                    <li><span class='title'>因子收益均值</span><span class='value'>{{ stats.beta_mean }}</span></li>
                    <li><span class='title'>因子收益标准差</span><span class='value'>{{ stats.beta_std }}</span></li>
                    <li><span class='title'>因子收益为正比率</span><span class='value'>{{ stats.positive_beta_ratio }}%</span></li>
                    <li><span class='title'>t值绝对值的均值</span><span class='value'>{{ stats.abs_t_mean }}</span></li>
                    <li><span class='title'>t值绝对值大于2的比率</span><span class='value'>{{ stats.abs_t_value_over_two_ratio }}</span></li>
                    <li><span class='title'>因子收益t检验p值小于0.05的比率</span><span class='value'>{{ stats.p_value_less_ratio }}</span></li>
                </ul>
            </div>
            """
            group_stats_template = """
            <div style="width:100%;text-align:center;color:#333333;margin-bottom:16px;font-size:12px;"><h2>{{ title }}</h2></div>
            <div class='kpicontainer'>
                <ul class='kpi'>
                    <li><span class='title'>&nbsp;</span>
                        {% for k in stats%}
                            <span class='value'>{{ k }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>收益率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].收益率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>近1日收益率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].近1日收益率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>近1周收益率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].近1周收益率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>近1月收益率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].近1月收益率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>年化收益率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].年化收益率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>夏普比率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].夏普比率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>收益波动率</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].收益波动率 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                    <li><span class='title'>最大回撤</span>
                        {% for k in stats%}
                            <span class='value'>{{ (stats[k].最大回撤 | string)[0:10] }}</span>
                        {% endfor %}
                    </li>
                 </ul>
            </div>
            """
    
            def __init__(self, ic_data, ic_summary, factor_returns_data, factor_returns_summary, quantile_returns_data, quantile_returns_summary):
                self.ic_df = ic_data
                self.ic_results = ic_summary
                self.ols_stats_df = factor_returns_data
                self.ols_stats_results = factor_returns_summary
                self.group_df = quantile_returns_data
                self.group_df_results = quantile_returns_summary
    
            def render_results(self, stats_template, results):
                """ 展示模板信息 """
    
                def render(stats_template, results):
                    html = Template(stats_template).render(stats=results["stats"], title=results["title"])
                    display_html(html)
    
                render(stats_template, results)
    
            def show_ic(self):
                self.render_results(self.ic_stats_template, self.ic_results)
                T.plot(
                    self.ic_df,
                    title="IC分析",
                    panes=[["ic", "40%"], ["ic_cumsum", "20%"]],
                    # height=500,设置高度为500
                    options={
                        "chart": {"height": 500},
                        # 设置颜色
                        "series": [
                            {
                                "name": "ic",
                                "color": "#8085e8",
                                "type": "column",
                                "yAxis": 0,
                            },
                            {
                                "name": "ic_cumsum",
                                "color": "#8d4653",
                                "type": "spline",
                                "yAxis": 0,
                            },
                        ],
                    },
                )
    
            def show_ols(self):
                self.render_results(self.ols_stats_template, self.ols_stats_results)
                T.plot(
                    self.ols_stats_df[["beta", "cum_beta", "roll_beta"]],
                    title="因子收益率",
                    # high、low显示在第一栏,高度40%,open、close显示在第二栏,其他的在最后一栏
                    panes=[["beta", "cum_beta", "40%"], ["roll_beta", "20%"]],
                    # height=500,设置高度为500
                    options={
                        "chart": {"height": 500},
                        # 设置颜色
                        "series": [
                            {
                                "name": "beta",
                                "color": "#8085e8",
                                "type": "column",
                                "yAxis": 0,
                            },
                            {
                                "name": "cum_beta",
                                "color": "#8d4653",
                                "type": "column",
                                "yAxis": 0,
                            },
                            {
                                "name": "roll_beta",
                                "color": "#91e8e1",
                                "type": "spline",
                                "yAxis": 1,
                            },
                        ],
                    },
                )
    
            def show_group(self):
                self.render_results(self.group_stats_template, self.group_df_results)
                T.plot(self.group_df[[i for i in self.group_df.columns if "_pv" in i]])
            
            def show(self):
                self.show_ic()
                self.show_ols()
                self.show_group()
        
        # 读取 IC,FactorReturns,QuantileReturns用作展示
        performance_data = outputs.data_2.read()
        for data in performance_data:
            ic_data = data["data"]["IC"]
            factor_returns_data = data["data"]["FactorReturns"]
            quantile_returns_data = data["data"]["QuantileReturns"]
            ic_summary = data["summary"]["IC"]
            factor_returns_summary = data["summary"]["FactorReturns"]
            quantile_returns_summary = data["summary"]["QuantileReturns"]
            renderhtml = RenderHtml(ic_data, ic_summary, factor_returns_data, factor_returns_summary, quantile_returns_data, quantile_returns_summary)
            renderhtml.show()
        return outputs
    
    
    m1 = M.input_features.v1(
        features="""factor=np.corrcoef(close.pct_change().fillna(0),amount)[0][1]
    
    """
    )
    
    m7 = M.instruments.v2(
        start_date='2020-01-02',
        end_date=T.live_run_param('trading_date', '2021-10-12'),
        market='CN_FUTURE',
        instrument_list="""A8888.DCE
    AG8888.SHF
    AL8888.SHF
    AU8888.SHF
    B8888.DCE
    BB8888.DCE
    BU8888.SHF
    # C88.DCE
    # CF88.CZC
    # CS88.DCE
    # CU88.SHF
    # FB88.DCE
    # FG88.CZC
    # FU88.SHF
    # HC88.SHF
    # I88.DCE
    # J88.DCE
    # JD88.DCE
    # JM88.DCE
    # JR88.CZC
    # L88.DCE
    # LR88.CZC
    # M88.DCE
    # MA88.CZC
    # OI88.CZC
    # P88.DCE
    # PB88.SHF
    # PM88.CZC
    # PP88.DCE
    # RB88.SHF
    # RM88.CZC 
    # RU88.SHF
    # SF88.CZC
    # SM88.CZC
    # SR88.CZC
    # TA88.CZC
    # TF88.CFX
    # V88.DCE
    # Y88.DCE
    # ZN88.SHF
    # NI88.SHF
    # SN88.SHF
    # ZC88.CZC
    # CY88.CZC
    # AP88.CZC
    # SC88.INE
    # SP88.SHF
    # EG88.DCE
    # EB88.DCE
    # SA88.CZC
    # PG88.DCE
    # LU88.INE
    # PF88.CZC""",
        max_count=0
    )
    
    m14 = M.feature_extractor_1m.v2(
        instruments=m7.data,
        features=m1.data,
        start_date='',
        end_date='',
        before_start_days=60,
        workers=1,
        parallel_mode='集群',
        table_1m='bar1m_CN_FUTURE'
    )
    
    m2 = M.input_features.v1(
        features="""factor
    
    """
    )
    
    m6 = M.cached.v3(
        input_1=m7.data,
        input_2=m14.data,
        input_3=m2.data,
        run=m6_run_bigquant_run,
        post_run=m6_post_run_bigquant_run,
        input_ports='input_1, input_2, input_3',
        params="""{
        'rabalance_period': 22,
        'buy_commission_rate': 0.0005,
        'sell_commission_rate': 0.0005,
        'ic_method': 'Rank_IC',
        'quantile_num': 5,
        'is_standardlize': True,
        'is_winsorize': True
    }""",
        output_ports='data_1, data_2',
        m_cached=False
    )
    
    m3 = M.factorlens_preservation.v1(
        factors_info=m6.data_1
    )
    

    factor: IC分析

    • IC均值-0.1071
    • IC标准差0.464
    • ICIR-0.2308
    • IC正值次数8次
    • IC负值次数11次
    • IC偏度0.3872
    • IC峰度-0.3103

    factor: 因子收益率分析

    • 因子收益均值-0.0058
    • 因子收益标准差0.025
    • 因子收益为正比率36.84%
    • t值绝对值的均值0.9998
    • t值绝对值大于2的比率0.1579
    • 因子收益t检验p值小于0.05的比率0.0526

    factor: 因子绩效分析

    •   top0_ret top4_ret LS_ret
    • 收益率 0.4287 0.0681 0.1017
    • 近1日收益率 0.0024 -0.0059 0.0041
    • 近1周收益率 0.0117 0.0049 0.0032
    • 近1月收益率 -0.0039 -0.0321 0.0142
    • 年化收益率 0.2362 0.0399 0.0593
    • 夏普比率 0.9733 0.172 0.2179
    • 收益波动率 0.2031 0.3157 0.1685
    • 最大回撤 -0.1673 -0.3389 -0.1759