复制链接
克隆策略
In [ ]:
PIT(point in time)

TTM:过去12个月单季度财务数据的加总净利润Q3,Q2
mrq:
lf:
ly:
_n:np_ly_0/np_ly_1 -1 

ROIC

ROIC 衡量的是股东和债权人投入的本钱,到底获取了多少回报? 假如企业赚到的钱是一个蛋糕,它最后会被三个人分走,支付的利息费用被债主拿走了,缴的税被国家拿走了,剩下的利润被股东拿走了。

ROE = 净利润/净资产:1.净利润容易被操控;2.净资产没有考虑债权人的利润 ROA衡量所有资产

【ROIC】投入资本回报率 |释义|:ROIC是生产经营活动中所有投入资本赚取的收益率,而不论这些投入资本是被称为债务还是权益。分子是指公司如果完全按权益筹资所应报告的税后利润,分母是指公司所有要求回报的现金来源的总和。。相对而言ROIC是比ROA和ROE更全面、更好的度量盈利能力的工具,是衡量一家公司真实经营业绩最好的度量指标,与ROE相比,ROIC去除了公司不同的融资结构对盈利能力造成的影响,使用ROIC将有助于投资者将关注的核心聚焦在核心业务的盈利能力上。 |公式|:EBIT反推法(1-有效税率)2/(期初全部投入资本+期末全部投入资本)

【有效税率】 |公式|:有效税率:当所得税>0时,为所得税/利润总额,否则为0

【EBIT正推法】 (营业总收入-营业税金及附加)-(营业成本+利息支出+手续费及佣金支出+销售费用+管理费用+研发费用+存货跌价损失+信用减值损失)+其他收益

【EBIT反推法】 |公式|:利润总额+利息费用(不含资本化利息支出) 如果财务报告中公布了财务费用明细,则“利息费用=(利息支出-财务费用明细.利息资本化金额)-利息收入”;如果财务报告中未公布财务费用明细,则以“利润表.利息费用 -利润表.利息收入 ”替代。一般而言,中期报告和年度报告中会公布财务费用明细。

【投入资本】 |释义|:投入资本指所有投资者(股权人、债权人)投入的资金总和,这些资金都是意图分享企业经营回报的。投入资本与总资产的核心差别在于投资资本中不包括无息负债。 股东权益(含少数股东权益)+负债合计-无息流动负债-无息长期负债

【无息流动负债】 |释义|:无息流动负债在资产负债表中主要表现为应付账款、应付工资、其他应付等。无息流动负债也是企业对其他方资金的一种占用,但这部分资金并不来自于投资人,这种资金占用只是企业正常经营活动中的一个必要环节,一种循环占用。 |公式|:应付帐款及应付票据+预收款项+应付职工薪酬+应交税费+其他应付款合计+预提费用+递延收益.流动负债+合同负债+其他流动负债-短期融资债(其他流动负债)+衍生金融负债

【无息非流动负债】 |释义|:无息非流动负债在资产负债表中主要体现为预计负债、长期应付款等。为了谨慎起见,我们采用间接法计算无息非流动负债。 |公式|:非流动负债合计-长期借款-应付债券

In [9]:
df = m5.data_1.read()[['date','instrument','roic_ttm_0']]
df[df.instrument=='000063.SZA']
Out[9]:
date instrument roic_ttm_0
2867 2019-10-08 000063.SZA 0.053537
2868 2019-10-09 000063.SZA 0.053537
2869 2019-10-10 000063.SZA 0.053537
2870 2019-10-11 000063.SZA 0.053537
2871 2019-10-14 000063.SZA 0.053537
... ... ... ...
238420 2020-12-25 000063.SZA 0.043285
238421 2020-12-28 000063.SZA 0.043285
238422 2020-12-29 000063.SZA 0.043285
238423 2020-12-30 000063.SZA 0.043285
238424 2020-12-31 000063.SZA 0.043285

304 rows × 3 columns

    {"description":"实验创建于2022/11/18","graph":{"edges":[{"to_node_id":"-168:features","from_node_id":"-155:data"},{"to_node_id":"-492:features","from_node_id":"-155:data"},{"to_node_id":"-168:instruments","from_node_id":"-159:data"},{"to_node_id":"-512:instruments","from_node_id":"-159:data"},{"to_node_id":"-492:input_data","from_node_id":"-168:data"},{"to_node_id":"-684:input_1","from_node_id":"-492:data"},{"to_node_id":"-1947:input_ds","from_node_id":"-684:data_1"},{"to_node_id":"-1623:input_data","from_node_id":"-684:data_1"},{"to_node_id":"-512:options_data","from_node_id":"-1947:sorted_data"},{"to_node_id":"-1598:user_factor_data","from_node_id":"-1623:data"},{"to_node_id":"-1598:features","from_node_id":"-1626:data"}],"nodes":[{"node_id":"-155","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"# 所得税费用\nincome_tax_cost_ttm_0\nincome_tax_cost_ttm_4\n# 利润总额\ntotal_profit_ttm_0\ntotal_profit_ttm_4\n# 财务费用:利息费用\ninterest_fee_ttm_0\ninterest_fee_ttm_4\n# 财务费用:利息收入\nfc_interest_income_ttm_0\nfc_interest_income_ttm_4\n# 财务费用\nfinancing_expenses_ttm_0\nfinancing_expenses_ttm_4\n# 所有者权益\ntotal_owner_equity_lf_0\ntotal_owner_equity_lf_4\n# 负债合计\ntotal_liab_lf_0\ntotal_liab_lf_4\n# 应收账款及应付票据\nbill_and_account_payable_lf_0\nbill_and_account_payable_lf_4\n# 预收款项\nadvance_payment_lf_0\nadvance_payment_lf_4\n# 应付职工薪酬\npayroll_payable_lf_0\npayroll_payable_lf_4\n# 应交税费\ntax_payable_lf_0\ntax_payable_lf_4\n# 其他应付款合计\nother_payables_sum_lf_0\nother_payables_sum_lf_4\n# 递延收益.流动负债\ndiffered_income_current_liab_lf_0\ndiffered_income_current_liab_lf_4\n# 合同负债\ncontract_liab_lf_0\ncontract_liab_lf_4\n# 其他流动负债\nother_current_liab_lf_0\nother_current_liab_lf_4\n# 衍生金融负债\nderivative_fnncl_liab_lf_0\nderivative_fnncl_liab_lf_4\n# 非流动负债合计\ntotal_noncurrent_liab_lf_0\ntotal_noncurrent_liab_lf_4\n# 长期借款\nlt_loan_lf_0\nlt_loan_lf_4\n# 应付债券\nbond_payable_lf_0\nbond_payable_lf_4","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-155"}],"output_ports":[{"name":"data","node_id":"-155"}],"cacheable":true,"seq_num":1,"comment":"","comment_collapsed":true},{"node_id":"-159","module_id":"BigQuantSpace.instruments.instruments-v2","parameters":[{"name":"start_date","value":"2020-01-01","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-01-01","type":"Literal","bound_global_parameter":null},{"name":"market","value":"CN_STOCK_A","type":"Literal","bound_global_parameter":null},{"name":"instrument_list","value":"","type":"Literal","bound_global_parameter":null},{"name":"max_count","value":0,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"rolling_conf","node_id":"-159"}],"output_ports":[{"name":"data","node_id":"-159"}],"cacheable":true,"seq_num":2,"comment":"","comment_collapsed":true},{"node_id":"-168","module_id":"BigQuantSpace.general_feature_extractor.general_feature_extractor-v7","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":90,"type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-168"},{"name":"features","node_id":"-168"}],"output_ports":[{"name":"data","node_id":"-168"}],"cacheable":true,"seq_num":3,"comment":"","comment_collapsed":true},{"node_id":"-492","module_id":"BigQuantSpace.derived_feature_extractor.derived_feature_extractor-v3","parameters":[{"name":"date_col","value":"date","type":"Literal","bound_global_parameter":null},{"name":"instrument_col","value":"instrument","type":"Literal","bound_global_parameter":null},{"name":"drop_na","value":"False","type":"Literal","bound_global_parameter":null},{"name":"remove_extra_columns","value":"False","type":"Literal","bound_global_parameter":null},{"name":"user_functions","value":"{}","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_data","node_id":"-492"},{"name":"features","node_id":"-492"}],"output_ports":[{"name":"data","node_id":"-492"}],"cacheable":true,"seq_num":4,"comment":"","comment_collapsed":true},{"node_id":"-684","module_id":"BigQuantSpace.cached.cached-v3","parameters":[{"name":"run","value":"# Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端\ndef bigquant_run(input_1, input_2, input_3):\n df = input_1.read()\n df.replace(np.nan, round(0, 1), inplace=True)\n \n # 无息流动负债\n df['noninterest_current_liab_lf_0'] = df['bill_and_account_payable_lf_0'] + df['advance_payment_lf_0'] + df['payroll_payable_lf_0'] + df['tax_payable_lf_0'] + df['other_payables_sum_lf_0'] + df['differed_income_current_liab_lf_0'] + df['contract_liab_lf_0'] + df['other_current_liab_lf_0'] + df['derivative_fnncl_liab_lf_0']\n df['noninterest_current_liab_lf_4'] = df['bill_and_account_payable_lf_4'] + df['advance_payment_lf_4'] + df['payroll_payable_lf_4'] + df['tax_payable_lf_4'] + df['other_payables_sum_lf_4'] + df['differed_income_current_liab_lf_4'] + df['contract_liab_lf_4'] + df['other_current_liab_lf_4'] + df['derivative_fnncl_liab_lf_4']\n\n # 无息非流动负债\n df['noninterest_noncurrent_liab_lf_0'] = df['total_noncurrent_liab_lf_0'] - df['lt_loan_lf_0'] - df['bond_payable_lf_0']\n df['noninterest_noncurrent_liab_lf_4'] = df['total_noncurrent_liab_lf_4'] - df['lt_loan_lf_4'] - df['bond_payable_lf_4']\n\n # 全部投入资本\n df['total_paidin_capital_lf_0'] = df['total_owner_equity_lf_0'] + (df['total_liab_lf_0'] - df['noninterest_current_liab_lf_0'] - df['noninterest_noncurrent_liab_lf_0'])\n df['total_paidin_capital_lf_4'] = df['total_owner_equity_lf_4'] + (df['total_liab_lf_4'] - df['noninterest_current_liab_lf_4'] - df['noninterest_noncurrent_liab_lf_4'])\n\n # 平均全部投入资本\n df['total_paidin_capital_ttm_mean'] = (df['total_paidin_capital_lf_0'] + df['total_paidin_capital_lf_4']) / 2\n \n # 是否有财务费用明细的数据打标签\n df['nan_tag_fs_interest_income_ttm_0'] = 0 # 财务费用明细有数据则为0,则不用财务费用科目的数据\n df.loc[(df['interest_fee_ttm_0']==0)&(df['fc_interest_income_ttm_0']==0), 'nan_tag_fs_interest_income_ttm_0'] = 1\n df['EBIT_ttm_0'] = df['total_profit_ttm_0'] + (df['interest_fee_ttm_0'] - df['fc_interest_income_ttm_0']) + df['financing_expenses_ttm_0'] * df['nan_tag_fs_interest_income_ttm_0']\n \n # 给利润总额为负的数据打标签\n df['neg_tag_total_profit'] = 1\n df.loc[df['total_profit_ttm_0']<0, 'neg_tag_total_profit'] = 0\n df['effective_tax_rate_ttm_0'] = (df['income_tax_cost_ttm_0'] * df['neg_tag_total_profit']) / df['total_profit_ttm_0']\n \n \n # 计算ROIC\n df['roic_ttm_0'] = (df['EBIT_ttm_0'] * (1 - df['effective_tax_rate_ttm_0'])) / df['total_paidin_capital_ttm_mean']\n data_1 = DataSource.write_df(df)\n return Outputs(data_1=data_1, data_2=None, data_3=None)\n","type":"Literal","bound_global_parameter":null},{"name":"post_run","value":"# 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。\ndef bigquant_run(outputs):\n return outputs\n","type":"Literal","bound_global_parameter":null},{"name":"input_ports","value":"","type":"Literal","bound_global_parameter":null},{"name":"params","value":"{}","type":"Literal","bound_global_parameter":null},{"name":"output_ports","value":"","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_1","node_id":"-684"},{"name":"input_2","node_id":"-684"},{"name":"input_3","node_id":"-684"}],"output_ports":[{"name":"data_1","node_id":"-684"},{"name":"data_2","node_id":"-684"},{"name":"data_3","node_id":"-684"}],"cacheable":true,"seq_num":5,"comment":"计算EBIT和有效税率","comment_collapsed":true},{"node_id":"-1947","module_id":"BigQuantSpace.sort.sort-v5","parameters":[{"name":"sort_by","value":"roic_ttm_0","type":"Literal","bound_global_parameter":null},{"name":"group_by","value":"date","type":"Literal","bound_global_parameter":null},{"name":"keep_columns","value":"--","type":"Literal","bound_global_parameter":null},{"name":"ascending","value":"False","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"input_ds","node_id":"-1947"},{"name":"sort_by_ds","node_id":"-1947"}],"output_ports":[{"name":"sorted_data","node_id":"-1947"}],"cacheable":true,"seq_num":6,"comment":"","comment_collapsed":true},{"node_id":"-512","module_id":"BigQuantSpace.trade.trade-v4","parameters":[{"name":"start_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"","type":"Literal","bound_global_parameter":null},{"name":"initialize","value":"# 回测引擎:初始化函数,只执行一次\ndef bigquant_run(context):\n # 加载预测数据\n context.ranker_prediction = context.options['data'].read_df()\n\n # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数\n context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))\n # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)\n # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只\n stock_count = 50\n # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]\n context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])\n # 设置每只股票占用的最大资金比例\n context.max_cash_per_instrument = 0.2\n context.options['hold_days'] = 5\n","type":"Literal","bound_global_parameter":null},{"name":"handle_data","value":"# 回测引擎:每日数据处理函数,每天执行一次\ndef bigquant_run(context, data):\n # 按日期过滤得到今日的预测数据\n ranker_prediction = context.ranker_prediction[\n context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]\n \n ranker_prediction = ranker_prediction.sort_values('roic_ttm_0',ascending=False)\n \n # 1. 资金分配\n # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金\n # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)\n is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)\n cash_avg = context.portfolio.portfolio_value / context.options['hold_days']\n cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)\n cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)\n positions = {e.symbol: p.amount * p.last_sale_price\n for e, p in context.perf_tracker.position_tracker.positions.items()}\n\n # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰\n if not is_staging and cash_for_sell > 0:\n equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}\n instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(\n lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))\n # print('rank order for sell %s' % instruments)\n for instrument in instruments:\n context.order_target(context.symbol(instrument), 0)\n cash_for_sell -= positions[instrument]\n if cash_for_sell <= 0:\n break\n\n # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票\n buy_cash_weights = context.stock_weights\n buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])\n max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument\n for i, instrument in enumerate(buy_instruments):\n cash = cash_for_buy * buy_cash_weights[i]\n if cash > max_cash_per_instrument - positions.get(instrument, 0):\n # 确保股票持仓量不会超过每次股票最大的占用资金量\n cash = max_cash_per_instrument - positions.get(instrument, 0)\n if cash > 0:\n context.order_value(context.symbol(instrument), cash)\n","type":"Literal","bound_global_parameter":null},{"name":"prepare","value":"# 回测引擎:准备数据,只执行一次\ndef bigquant_run(context):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"before_trading_start","value":"# 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。\ndef bigquant_run(context, data):\n pass\n","type":"Literal","bound_global_parameter":null},{"name":"volume_limit","value":0.025,"type":"Literal","bound_global_parameter":null},{"name":"order_price_field_buy","value":"open","type":"Literal","bound_global_parameter":null},{"name":"order_price_field_sell","value":"close","type":"Literal","bound_global_parameter":null},{"name":"capital_base","value":"1000000","type":"Literal","bound_global_parameter":null},{"name":"auto_cancel_non_tradable_orders","value":"True","type":"Literal","bound_global_parameter":null},{"name":"data_frequency","value":"daily","type":"Literal","bound_global_parameter":null},{"name":"price_type","value":"真实价格","type":"Literal","bound_global_parameter":null},{"name":"product_type","value":"股票","type":"Literal","bound_global_parameter":null},{"name":"plot_charts","value":"True","type":"Literal","bound_global_parameter":null},{"name":"backtest_only","value":"False","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"000300.HIX","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"instruments","node_id":"-512"},{"name":"options_data","node_id":"-512"},{"name":"history_ds","node_id":"-512"},{"name":"benchmark_ds","node_id":"-512"},{"name":"trading_calendar","node_id":"-512"}],"output_ports":[{"name":"raw_perf","node_id":"-512"}],"cacheable":false,"seq_num":7,"comment":"","comment_collapsed":true},{"node_id":"-1598","module_id":"BigQuantSpace.factorlens.factorlens-v2","parameters":[{"name":"title","value":"因子分析: {factor_name}","type":"Literal","bound_global_parameter":null},{"name":"start_date","value":"2019-01-01","type":"Literal","bound_global_parameter":null},{"name":"end_date","value":"2021-10-01","type":"Literal","bound_global_parameter":null},{"name":"rebalance_period","value":22,"type":"Literal","bound_global_parameter":null},{"name":"delay_rebalance_days","value":0,"type":"Literal","bound_global_parameter":null},{"name":"rebalance_price","value":"close_0","type":"Literal","bound_global_parameter":null},{"name":"stock_pool","value":"全市场","type":"Literal","bound_global_parameter":null},{"name":"quantile_count","value":5,"type":"Literal","bound_global_parameter":null},{"name":"commission_rate","value":0.0016,"type":"Literal","bound_global_parameter":null},{"name":"returns_calculation_method","value":"累乘","type":"Literal","bound_global_parameter":null},{"name":"benchmark","value":"无","type":"Literal","bound_global_parameter":null},{"name":"drop_new_stocks","value":60,"type":"Literal","bound_global_parameter":null},{"name":"drop_price_limit_stocks","value":"True","type":"Literal","bound_global_parameter":null},{"name":"drop_st_stocks","value":"True","type":"Literal","bound_global_parameter":null},{"name":"drop_suspended_stocks","value":"True","type":"Literal","bound_global_parameter":null},{"name":"cutoutliers","value":"True","type":"Literal","bound_global_parameter":null},{"name":"normalization","value":"True","type":"Literal","bound_global_parameter":null},{"name":"neutralization","value":"%7B%22enumItems%22%3A%5B%7B%22value%22%3A%22%E8%A1%8C%E4%B8%9A%22%2C%22displayValue%22%3A%22%E8%A1%8C%E4%B8%9A%22%2C%22selected%22%3Afalse%7D%2C%7B%22value%22%3A%22%E5%B8%82%E5%80%BC%22%2C%22displayValue%22%3A%22%E5%B8%82%E5%80%BC%22%2C%22selected%22%3Afalse%7D%5D%7D","type":"Literal","bound_global_parameter":null},{"name":"metrics","value":"%7B%22enumItems%22%3A%5B%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E8%A1%A8%E7%8E%B0%E6%A6%82%E8%A7%88%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E8%A1%A8%E7%8E%B0%E6%A6%82%E8%A7%88%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E5%88%86%E5%B8%83%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E5%88%86%E5%B8%83%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E8%A1%8C%E4%B8%9A%E5%88%86%E5%B8%83%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E8%A1%8C%E4%B8%9A%E5%88%86%E5%B8%83%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E5%B8%82%E5%80%BC%E5%88%86%E5%B8%83%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E5%B8%82%E5%80%BC%E5%88%86%E5%B8%83%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22IC%E5%88%86%E6%9E%90%22%2C%22displayValue%22%3A%22IC%E5%88%86%E6%9E%90%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E4%B9%B0%E5%85%A5%E4%BF%A1%E5%8F%B7%E9%87%8D%E5%90%88%E5%88%86%E6%9E%90%22%2C%22displayValue%22%3A%22%E4%B9%B0%E5%85%A5%E4%BF%A1%E5%8F%B7%E9%87%8D%E5%90%88%E5%88%86%E6%9E%90%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E4%BC%B0%E5%80%BC%E5%88%86%E6%9E%90%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E4%BC%B0%E5%80%BC%E5%88%86%E6%9E%90%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E6%8B%A5%E6%8C%A4%E5%BA%A6%E5%88%86%E6%9E%90%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E6%8B%A5%E6%8C%A4%E5%BA%A6%E5%88%86%E6%9E%90%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%9B%A0%E5%AD%90%E5%80%BC%E6%9C%80%E5%A4%A7%2F%E6%9C%80%E5%B0%8F%E8%82%A1%E7%A5%A8%22%2C%22displayValue%22%3A%22%E5%9B%A0%E5%AD%90%E5%80%BC%E6%9C%80%E5%A4%A7%2F%E6%9C%80%E5%B0%8F%E8%82%A1%E7%A5%A8%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9B%A0%E5%AD%90%E5%80%BC%22%2C%22displayValue%22%3A%22%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%9B%A0%E5%AD%90%E5%80%BC%22%2C%22selected%22%3Atrue%7D%2C%7B%22value%22%3A%22%E5%A4%9A%E5%9B%A0%E5%AD%90%E7%9B%B8%E5%85%B3%E6%80%A7%E5%88%86%E6%9E%90%22%2C%22displayValue%22%3A%22%E5%A4%9A%E5%9B%A0%E5%AD%90%E7%9B%B8%E5%85%B3%E6%80%A7%E5%88%86%E6%9E%90%22%2C%22selected%22%3Atrue%7D%5D%7D","type":"Literal","bound_global_parameter":null},{"name":"factor_coverage","value":0.5,"type":"Literal","bound_global_parameter":null},{"name":"user_data_merge","value":"left","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features","node_id":"-1598"},{"name":"user_factor_data","node_id":"-1598"}],"output_ports":[{"name":"data","node_id":"-1598"},{"name":"save_data","node_id":"-1598"}],"cacheable":true,"seq_num":8,"comment":"","comment_collapsed":true},{"node_id":"-1623","module_id":"BigQuantSpace.dropnan.dropnan-v2","parameters":[],"input_ports":[{"name":"input_data","node_id":"-1623"},{"name":"features","node_id":"-1623"}],"output_ports":[{"name":"data","node_id":"-1623"}],"cacheable":true,"seq_num":9,"comment":"","comment_collapsed":true},{"node_id":"-1626","module_id":"BigQuantSpace.input_features.input_features-v1","parameters":[{"name":"features","value":"roic_ttm_0","type":"Literal","bound_global_parameter":null}],"input_ports":[{"name":"features_ds","node_id":"-1626"}],"output_ports":[{"name":"data","node_id":"-1626"}],"cacheable":true,"seq_num":10,"comment":"","comment_collapsed":true}],"node_layout":"<node_postions><node_position Node='-155' Position='388,357,200,200'/><node_position Node='-159' Position='62,356,200,200'/><node_position Node='-168' Position='209,497,200,200'/><node_position Node='-492' Position='250,591,200,200'/><node_position Node='-684' Position='249,706,200,200'/><node_position Node='-1947' Position='240,814,200,200'/><node_position Node='-512' Position='135,938,200,200'/><node_position Node='-1598' Position='623,931,200,200'/><node_position Node='-1623' Position='616,814,200,200'/><node_position Node='-1626' Position='609,693,200,200'/></node_postions>"},"nodes_readonly":false,"studio_version":"v2"}
    In [5]:
    # 本代码由可视化策略环境自动生成 2022年11月21日 13:45
    # 本代码单元只能在可视化模式下编辑。您也可以拷贝代码,粘贴到新建的代码单元或者策略,然后修改。
    
    
    # Python 代码入口函数,input_1/2/3 对应三个输入端,data_1/2/3 对应三个输出端
    def m5_run_bigquant_run(input_1, input_2, input_3):
        df = input_1.read()
        df.replace(np.nan, round(0, 1), inplace=True)
        
        # 无息流动负债
        df['noninterest_current_liab_lf_0'] = df['bill_and_account_payable_lf_0'] + df['advance_payment_lf_0'] + df['payroll_payable_lf_0'] + df['tax_payable_lf_0'] + df['other_payables_sum_lf_0'] + df['differed_income_current_liab_lf_0'] + df['contract_liab_lf_0'] + df['other_current_liab_lf_0'] + df['derivative_fnncl_liab_lf_0']
        df['noninterest_current_liab_lf_4'] = df['bill_and_account_payable_lf_4'] + df['advance_payment_lf_4'] + df['payroll_payable_lf_4'] + df['tax_payable_lf_4'] + df['other_payables_sum_lf_4'] + df['differed_income_current_liab_lf_4'] + df['contract_liab_lf_4'] + df['other_current_liab_lf_4'] + df['derivative_fnncl_liab_lf_4']
    
        # 无息非流动负债
        df['noninterest_noncurrent_liab_lf_0'] = df['total_noncurrent_liab_lf_0'] - df['lt_loan_lf_0'] - df['bond_payable_lf_0']
        df['noninterest_noncurrent_liab_lf_4'] = df['total_noncurrent_liab_lf_4'] - df['lt_loan_lf_4'] - df['bond_payable_lf_4']
    
        # 全部投入资本
        df['total_paidin_capital_lf_0'] = df['total_owner_equity_lf_0'] + (df['total_liab_lf_0'] - df['noninterest_current_liab_lf_0'] - df['noninterest_noncurrent_liab_lf_0'])
        df['total_paidin_capital_lf_4'] = df['total_owner_equity_lf_4'] + (df['total_liab_lf_4'] - df['noninterest_current_liab_lf_4'] - df['noninterest_noncurrent_liab_lf_4'])
    
        # 平均全部投入资本
        df['total_paidin_capital_ttm_mean'] = (df['total_paidin_capital_lf_0'] + df['total_paidin_capital_lf_4']) / 2
        
        # 是否有财务费用明细的数据打标签
        df['nan_tag_fs_interest_income_ttm_0'] = 0    # 财务费用明细有数据则为0,则不用财务费用科目的数据
        df.loc[(df['interest_fee_ttm_0']==0)&(df['fc_interest_income_ttm_0']==0), 'nan_tag_fs_interest_income_ttm_0'] = 1
        df['EBIT_ttm_0'] = df['total_profit_ttm_0'] + (df['interest_fee_ttm_0'] - df['fc_interest_income_ttm_0']) + df['financing_expenses_ttm_0'] * df['nan_tag_fs_interest_income_ttm_0']
        
        # 给利润总额为负的数据打标签
        df['neg_tag_total_profit'] = 1
        df.loc[df['total_profit_ttm_0']<0, 'neg_tag_total_profit'] = 0
        df['effective_tax_rate_ttm_0'] = (df['income_tax_cost_ttm_0'] * df['neg_tag_total_profit']) / df['total_profit_ttm_0']
        
        
        # 计算ROIC
        df['roic_ttm_0'] = (df['EBIT_ttm_0'] * (1 - df['effective_tax_rate_ttm_0'])) / df['total_paidin_capital_ttm_mean']
        data_1 = DataSource.write_df(df)
        return Outputs(data_1=data_1, data_2=None, data_3=None)
    
    # 后处理函数,可选。输入是主函数的输出,可以在这里对数据做处理,或者返回更友好的outputs数据格式。此函数输出不会被缓存。
    def m5_post_run_bigquant_run(outputs):
        return outputs
    
    # 回测引擎:初始化函数,只执行一次
    def m7_initialize_bigquant_run(context):
        # 加载预测数据
        context.ranker_prediction = context.options['data'].read_df()
    
        # 系统已经设置了默认的交易手续费和滑点,要修改手续费可使用如下函数
        context.set_commission(PerOrder(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
        # 预测数据,通过options传入进来,使用 read_df 函数,加载到内存 (DataFrame)
        # 设置买入的股票数量,这里买入预测股票列表排名靠前的5只
        stock_count = 50
        # 每只的股票的权重,如下的权重分配会使得靠前的股票分配多一点的资金,[0.339160, 0.213986, 0.169580, ..]
        context.stock_weights = T.norm([1 / math.log(i + 2) for i in range(0, stock_count)])
        # 设置每只股票占用的最大资金比例
        context.max_cash_per_instrument = 0.2
        context.options['hold_days'] = 5
    
    # 回测引擎:每日数据处理函数,每天执行一次
    def m7_handle_data_bigquant_run(context, data):
        # 按日期过滤得到今日的预测数据
        ranker_prediction = context.ranker_prediction[
            context.ranker_prediction.date == data.current_dt.strftime('%Y-%m-%d')]
        
        ranker_prediction = ranker_prediction.sort_values('roic_ttm_0',ascending=False)
        
        # 1. 资金分配
        # 平均持仓时间是hold_days,每日都将买入股票,每日预期使用 1/hold_days 的资金
        # 实际操作中,会存在一定的买入误差,所以在前hold_days天,等量使用资金;之后,尽量使用剩余资金(这里设置最多用等量的1.5倍)
        is_staging = context.trading_day_index < context.options['hold_days'] # 是否在建仓期间(前 hold_days 天)
        cash_avg = context.portfolio.portfolio_value / context.options['hold_days']
        cash_for_buy = min(context.portfolio.cash, (1 if is_staging else 1.5) * cash_avg)
        cash_for_sell = cash_avg - (context.portfolio.cash - cash_for_buy)
        positions = {e.symbol: p.amount * p.last_sale_price
                     for e, p in context.perf_tracker.position_tracker.positions.items()}
    
        # 2. 生成卖出订单:hold_days天之后才开始卖出;对持仓的股票,按机器学习算法预测的排序末位淘汰
        if not is_staging and cash_for_sell > 0:
            equities = {e.symbol: e for e, p in context.perf_tracker.position_tracker.positions.items()}
            instruments = list(reversed(list(ranker_prediction.instrument[ranker_prediction.instrument.apply(
                    lambda x: x in equities and not context.has_unfinished_sell_order(equities[x]))])))
            # print('rank order for sell %s' % instruments)
            for instrument in instruments:
                context.order_target(context.symbol(instrument), 0)
                cash_for_sell -= positions[instrument]
                if cash_for_sell <= 0:
                    break
    
        # 3. 生成买入订单:按机器学习算法预测的排序,买入前面的stock_count只股票
        buy_cash_weights = context.stock_weights
        buy_instruments = list(ranker_prediction.instrument[:len(buy_cash_weights)])
        max_cash_per_instrument = context.portfolio.portfolio_value * context.max_cash_per_instrument
        for i, instrument in enumerate(buy_instruments):
            cash = cash_for_buy * buy_cash_weights[i]
            if cash > max_cash_per_instrument - positions.get(instrument, 0):
                # 确保股票持仓量不会超过每次股票最大的占用资金量
                cash = max_cash_per_instrument - positions.get(instrument, 0)
            if cash > 0:
                context.order_value(context.symbol(instrument), cash)
    
    # 回测引擎:准备数据,只执行一次
    def m7_prepare_bigquant_run(context):
        pass
    
    # 回测引擎:每个单位时间开始前调用一次,即每日开盘前调用一次。
    def m7_before_trading_start_bigquant_run(context, data):
        pass
    
    
    m1 = M.input_features.v1(
        features="""# 所得税费用
    income_tax_cost_ttm_0
    income_tax_cost_ttm_4
    # 利润总额
    total_profit_ttm_0
    total_profit_ttm_4
    # 财务费用:利息费用
    interest_fee_ttm_0
    interest_fee_ttm_4
    # 财务费用:利息收入
    fc_interest_income_ttm_0
    fc_interest_income_ttm_4
    # 财务费用
    financing_expenses_ttm_0
    financing_expenses_ttm_4
    # 所有者权益
    total_owner_equity_lf_0
    total_owner_equity_lf_4
    # 负债合计
    total_liab_lf_0
    total_liab_lf_4
    # 应收账款及应付票据
    bill_and_account_payable_lf_0
    bill_and_account_payable_lf_4
    # 预收款项
    advance_payment_lf_0
    advance_payment_lf_4
    # 应付职工薪酬
    payroll_payable_lf_0
    payroll_payable_lf_4
    # 应交税费
    tax_payable_lf_0
    tax_payable_lf_4
    # 其他应付款合计
    other_payables_sum_lf_0
    other_payables_sum_lf_4
    # 递延收益.流动负债
    differed_income_current_liab_lf_0
    differed_income_current_liab_lf_4
    # 合同负债
    contract_liab_lf_0
    contract_liab_lf_4
    # 其他流动负债
    other_current_liab_lf_0
    other_current_liab_lf_4
    # 衍生金融负债
    derivative_fnncl_liab_lf_0
    derivative_fnncl_liab_lf_4
    # 非流动负债合计
    total_noncurrent_liab_lf_0
    total_noncurrent_liab_lf_4
    # 长期借款
    lt_loan_lf_0
    lt_loan_lf_4
    # 应付债券
    bond_payable_lf_0
    bond_payable_lf_4"""
    )
    
    m2 = M.instruments.v2(
        start_date='2020-01-01',
        end_date='2021-01-01',
        market='CN_STOCK_A',
        instrument_list='',
        max_count=0
    )
    
    m3 = M.general_feature_extractor.v7(
        instruments=m2.data,
        features=m1.data,
        start_date='',
        end_date='',
        before_start_days=90
    )
    
    m4 = M.derived_feature_extractor.v3(
        input_data=m3.data,
        features=m1.data,
        date_col='date',
        instrument_col='instrument',
        drop_na=False,
        remove_extra_columns=False,
        user_functions={}
    )
    
    m5 = M.cached.v3(
        input_1=m4.data,
        run=m5_run_bigquant_run,
        post_run=m5_post_run_bigquant_run,
        input_ports='',
        params='{}',
        output_ports=''
    )
    
    m6 = M.sort.v5(
        input_ds=m5.data_1,
        sort_by='roic_ttm_0',
        group_by='date',
        keep_columns='--',
        ascending=False
    )
    
    m9 = M.dropnan.v2(
        input_data=m5.data_1
    )
    
    m7 = M.trade.v4(
        instruments=m2.data,
        options_data=m6.sorted_data,
        start_date='',
        end_date='',
        initialize=m7_initialize_bigquant_run,
        handle_data=m7_handle_data_bigquant_run,
        prepare=m7_prepare_bigquant_run,
        before_trading_start=m7_before_trading_start_bigquant_run,
        volume_limit=0.025,
        order_price_field_buy='open',
        order_price_field_sell='close',
        capital_base=1000000,
        auto_cancel_non_tradable_orders=True,
        data_frequency='daily',
        price_type='真实价格',
        product_type='股票',
        plot_charts=True,
        backtest_only=False,
        benchmark='000300.HIX'
    )
    
    m10 = M.input_features.v1(
        features='roic_ttm_0'
    )
    
    m8 = M.factorlens.v2(
        features=m10.data,
        user_factor_data=m9.data,
        title='因子分析: {factor_name}',
        start_date='2019-01-01',
        end_date='2021-10-01',
        rebalance_period=22,
        delay_rebalance_days=0,
        rebalance_price='close_0',
        stock_pool='全市场',
        quantile_count=5,
        commission_rate=0.0016,
        returns_calculation_method='累乘',
        benchmark='无',
        drop_new_stocks=60,
        drop_price_limit_stocks=True,
        drop_st_stocks=True,
        drop_suspended_stocks=True,
        cutoutliers=True,
        normalization=True,
        neutralization=[],
        metrics=['因子表现概览', '因子分布', '因子行业分布', '因子市值分布', 'IC分析', '买入信号重合分析', '因子估值分析', '因子拥挤度分析', '因子值最大/最小股票', '表达式因子值', '多因子相关性分析'],
        factor_coverage=0.5,
        user_data_merge='left'
    )
    
    • 收益率-19.03%
    • 年化收益率-19.66%
    • 基准收益率27.21%
    • 阿尔法-0.27
    • 贝塔0.35
    • 夏普比率-1.19
    • 胜率0.47
    • 盈亏比0.94
    • 收益波动率19.36%
    • 信息比率-0.13
    • 最大回撤28.91%
    bigcharts-data-start/{"__type":"tabs","__id":"bigchart-3d8949f779ab4950a55d72280b6e5302"}/bigcharts-data-end