{"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'> </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"}
[2021-10-18 13:34:08.114232] INFO: moduleinvoker: input_features.v1 开始运行..
[2021-10-18 13:34:08.124009] INFO: moduleinvoker: 命中缓存
[2021-10-18 13:34:08.125448] INFO: moduleinvoker: input_features.v1 运行完成[0.011225s].
[2021-10-18 13:34:08.130303] INFO: moduleinvoker: instruments.v2 开始运行..
[2021-10-18 13:34:08.142033] INFO: moduleinvoker: 命中缓存
[2021-10-18 13:34:08.143398] INFO: moduleinvoker: instruments.v2 运行完成[0.013092s].
[2021-10-18 13:34:08.151833] INFO: moduleinvoker: feature_extractor_1m.v2 开始运行..
[2021-10-18 13:34:08.160994] INFO: moduleinvoker: 命中缓存
[2021-10-18 13:34:08.162192] INFO: moduleinvoker: feature_extractor_1m.v2 运行完成[0.010357s].
[2021-10-18 13:34:08.165784] INFO: moduleinvoker: input_features.v1 开始运行..
[2021-10-18 13:34:08.175878] INFO: moduleinvoker: 命中缓存
[2021-10-18 13:34:08.177249] INFO: moduleinvoker: input_features.v1 运行完成[0.011482s].
[2021-10-18 13:34:08.209458] INFO: moduleinvoker: cached.v3 开始运行..
[2021-10-18 13:34:12.113658] INFO: moduleinvoker: cached.v3 运行完成[3.904214s].
[2021-10-18 13:34:12.120012] INFO: moduleinvoker: factorlens_preservation.v1 开始运行..
[2021-10-18 13:34:12.131473] INFO: 保存因子: 开始保存因子: factor
[2021-10-18 13:34:12.132510] INFO: 保存因子: factor数据格式无误,可以提交任务
[2021-10-18 13:34:12.169582] INFO: moduleinvoker: factorlens_preservation.v1 运行完成[0.049566s].
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