def Momentum017(cls, data: pd.DataFrame, open_price: str = PVN.OPEN.value, close_price: str = PVN.CLOSE.value, n: int = 1) -> DataInfo: """ 动量OTC收益率均值(MTM_OTC):N日开盘价与收盘价收益率均值 :return: """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['return'] = data.groupby(KN.STOCK_ID.value, group_keys=False).apply( lambda x: (x[open_price] / x[close_price].shift(1) - 1).shift(-1)) data[factor_name] = data['return'].groupby(KN.STOCK_ID.value, group_keys=False).rolling(n, min_periods=1).mean() F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def load_factor(self, fact_name: str, fact_params: Dict[str, Any], fact_value: pd.DataFrame = None, **kwargs) -> DataInfo: """ 优先直接获取数据--否则实时计算 """ if fact_value is None: print( f"{dt.datetime.now().strftime('%X')}: Starting calculate the factors!" ) try: factRawData = self.factor[fact_name + '_data_raw'](**fact_params) except Exception as e: print( f"{dt.datetime.now().strftime('%X')}: Unable to load raw data that to calculate factor!-{e}" ) factClass = DataInfo() else: factClass = self.factor[fact_name](data=factRawData, **fact_params) else: print( f"{dt.datetime.now().strftime('%X')}: Get factor data from input!" ) fact_value = fact_value.set_index( [KN.TRADE_DATE.value, KN.STOCK_ID.value]) factClass = DataInfo() factClass.data = fact_value[fact_name] factClass.data_name = fact_name return factClass
def Profit013(cls, data: pd.DataFrame, net_profit_in: str = FISN.Net_Pro_In.value, total_asset: str = FBSN.Total_Asset.value, switch: bool = False): """ 总资产净利率(TTM)(ROA_TTM) """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[net_profit_in] / data[total_asset] data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data.reset_index(inplace=True) F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Value008(cls, data: pd.DataFrame, Surplus_Reserves: str = FBSN.Surplus_Reserves.value, Undistributed_Profit: str = FBSN.Undistributed_Profit.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False): """ 股息率倒数(DP_TTM):股息率(近12个月现金红利和) 股息 = 期末留存收益 - 期初留存收益 留存收益 = 盈余公积 + 未分配利润 """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data["RE"] = data[Surplus_Reserves] + data[Undistributed_Profit] data[func_name] = data["RE"] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Value011(cls, data: pd.DataFrame, net_asset_ex: str = FBSN.Net_Asset_Ex.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False) -> DataInfo: """ 市净率倒数(TTM)(BP_TTM):市净率的倒数 :param data: :param net_asset_ex: :param total_mv: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[net_asset_ex] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Value014(cls, data: pd.DataFrame, free_cash_flow: str = FCFSN.Free_Cash_Flow.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False): """ 市现率倒数(自由现金流,TTM)(FCFP_TTM):市现率倒数(自由现金流) :param data: :param free_cash_flow: :param total_mv: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[free_cash_flow] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Momentum009(cls, data: pd.DataFrame, close_price: str = PVN.CLOSE.value, bm_price: str = 'index_close', n: int = 20): """ 市场alpha因子 """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # ret data = data.groupby(KN.STOCK_ID.value).pct_change().dropna() data_new = data.groupby(KN.STOCK_ID.value, group_keys=False).apply( lambda x: cls._reg_rolling(x, bm_price, close_price, False, True, n)) data_new.name = factor_name F = DataInfo() F.data = data_new F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def Momentum025(cls, data: pd.DataFrame, high_price: str = PVN.HIGH.value, close_price: str = PVN.CLOSE.value, n: int = 1) -> DataInfo: """ 动量CTH收益率绝对值均值(MTM_CTH_abs):N日收盘价与最高价收益率绝对值均值 :return: """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['return'] = data.groupby(KN.STOCK_ID.value, group_keys=False).apply(lambda x: abs(x[close_price] / x[high_price] - 1)) data[factor_name] = data['return'].groupby(KN.STOCK_ID.value, group_keys=False).rolling(n, min_periods=1).mean() F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def Value004(cls, data: pd.DataFrame, operator_income: str = FISN.Op_Income.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False): """ 市销率倒数(TTM)(SP_TTM):市销率倒数 :param data: :param operator_income: :param total_mv: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[operator_income] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Profit026(cls, data: pd.DataFrame, net_profit_in: str = FISN.Net_Pro_In.value, operator_income: str = FISN.Op_Income.value, switch: bool = False): """ 当期净利润率(NP) """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[net_profit_in] / data[operator_income] data[np.isinf(data[func_name])] = 0 if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Momentum012(cls, data: pd.DataFrame, price: str = PVN.CLOSE.value, n: int = 20): """ 路径动量因子(MTM_PathLen) """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['stand'] = data[price].groupby(KN.STOCK_ID.value, group_keys=False).apply( lambda x: (x - x.rolling(n, min_periods=1).mean()) / x.rolling(n, min_periods=1).std(ddof=1)) data['stand'][np.isinf(data['stand'])] = np.nan data['diff'] = data['stand'].groupby(KN.STOCK_ID.value).diff(1).abs() data[factor_name] = data['diff'].groupby(KN.STOCK_ID.value, group_keys=False).rolling(n, min_periods=1).sum() F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def Value009(cls, data: pd.DataFrame, operator_income: str = FISN.Op_Income.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False): """ 企业价值倍数倒数(最新财报,扣除现金)(EV2EBITDA_LR):企业价值(扣除现金)/息税折旧摊销前利润 企业价值 = 总市值 + 负债总计 - 无息负债 - 货币资金 :param data: :param operator_income: :param total_mv: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[operator_income] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Value002(cls, data: pd.DataFrame, net_profit_cut: str = FISN.Net_Pro_Cut.value, total_mv: str = PVN.TOTAL_MV.value, switch: bool = False): """ 扣非市盈率倒数(EP_cut_TTM): 市盈率(扣除非经常性损益)倒数 :param data: :param net_profit_cut: :param total_mv: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[net_profit_cut] / data[total_mv] data_fact = data[func_name].copy(deep=True) data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Solvency017(cls, data: pd.DataFrame, total_asset: str = FBSN.Total_Asset.value, currency: str = FBSN.Currency.value, tradable_asset: str = FBSN.Tradable_Asset.value, op_net_cash_flow: str = FCFSN.Op_Net_CF.value, short_borrow: str = FBSN.ST_Borrow.value, short_bond_payable: str = FBSN.ST_Bond_Payable.value, short_iliq_liability_1y: str = FBSN.ST_IL_LB_1Y.value, quarter: int = 8, switch: bool = False): """ 短期偿债能力指标1(ShortDebt2_CFPA_std):(现金及现金等价物 + TTM经营性现金流 - 短期有息负债)/ 总资产 现金及现金等价物 = 货币资金 + 交易性金融资产 经营性现金流 = 经营性现金流量净额 短期有息负债 = 短期借款 + 短期应付债券 + 一年内到期的非流动负债 :param data: :param total_asset: :param currency: :param tradable_asset: :param op_net_cash_flow: :param short_borrow: :param short_bond_payable: :param short_iliq_liability_1y: :param quarter: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) x1 = data[[currency, tradable_asset, op_net_cash_flow]].sum(skipna=True, axis=1) x2 = data[[short_borrow, short_bond_payable, short_iliq_liability_1y]].sum(skipna=True, axis=1) y = data[total_asset] # 短期偿债能力指标 ShortDebt2_CFPA = (x1 - x2) / y data[func_name] = ShortDebt2_CFPA.groupby(KN.STOCK_ID.value).apply(lambda x: - x.rolling(quarter).std()) # switch inf to Nan data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Solvency010(cls, data: pd.DataFrame, currency: str = FBSN.Currency.value, tradable_asset: str = FBSN.Tradable_Asset.value, op_net_cash_flow: str = FCFSN.Op_Net_CF.value, short_borrow: str = FBSN.ST_Borrow.value, short_bond_payable: str = FBSN.ST_Bond_Payable.value, short_iliq_liability_1y: str = FBSN.ST_IL_LB_1Y.value, switch: bool = False) -> DataInfo: """ 短期偿债能力指标1(ShortDebt1_CFPA_qoq):(现金及现金等价物 + TTM经营性现金流)/短期有息负债 现金及现金等价物 = 货币资金 + 交易性金融资产 经营性现金流 = 经营性现金流量净额 短期有息负债 = 短期借款 + 短期应付债券 + 一年内到期的非流动负债 :param data: :param currency: :param tradable_asset: :param op_net_cash_flow: :param short_borrow: :param short_bond_payable: :param short_iliq_liability_1y: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # 短期偿债能力指标 ShortDebt1_CFPA = data[[currency, tradable_asset, op_net_cash_flow]].sum(skipna=True, axis=1) / \ data[[short_borrow, short_bond_payable, short_iliq_liability_1y]].sum(skipna=True, axis=1) # switch inf to Nan ShortDebt1_CFPA[np.isinf(ShortDebt1_CFPA)] = np.nan data[func_name] = ShortDebt1_CFPA.groupby(KN.STOCK_ID.value).apply(lambda x: x.diff(1) / abs(x.shift(1))) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Solvency012(cls, data: pd.DataFrame, total_asset: str = FBSN.Total_Asset.value, currency: str = FBSN.Currency.value, tradable_asset: str = FBSN.Tradable_Asset.value, short_borrow: str = FBSN.ST_Borrow.value, short_bond_payable: str = FBSN.ST_Bond_Payable.value, short_iliq_liability_1y: str = FBSN.ST_IL_LB_1Y.value, switch: bool = False): """ 短期偿债能力指标3(ShortDebt3_CFPA_qoq):(现金及现金等价物 - 短期有息负债)/ 总资产 现金及现金等价物 = 货币资金 + 交易性金融资产 短期有息负债 = 短期借款 + 短期应付债券 + 一年内到期的非流动负债 :param data: :param total_asset: :param currency: :param tradable_asset: :param short_borrow: :param short_bond_payable: :param short_iliq_liability_1y: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) x1 = data[[currency, tradable_asset]].sum(skipna=True, axis=1) x2 = data[[short_borrow, short_bond_payable, short_iliq_liability_1y]].sum(skipna=True, axis=1) y = data[total_asset] # 短期偿债能力指标 ShortDebt2_CFPA = (x1 - x2) / y data[func_name] = ShortDebt2_CFPA.groupby(KN.STOCK_ID.value).apply(lambda x: x.diff(1) / abs(x.shift(1))) # switch inf to Nan data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Quality008(cls, data: pd.DataFrame, op_net_cash_flow: str = FCFSN.Op_Net_CF.value, operator_profit: str = FISN.Op_Pro.value, switch: bool = False): """ 应计利润占比(APR) = 应计利润 / 营业利润 应计利润 = 营业利润 - 经营性现金流量净额 :param data: :param op_net_cash_flow: :param operator_profit: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # 缺失科目填补为0 data[op_net_cash_flow].fillna(0, inplace=True) data[func_name] = (data[operator_profit] - data[op_net_cash_flow]) / data[operator_profit] data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Operate007(cls, data: pd.DataFrame, operator_income: str = FISN.Op_Income.value, operator_cost: str = FISN.Op_Cost.value, quarter: int = 8, switch: bool = False): """ 营业能力改善因子(RROC_N) """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # 标准化 reg_input = data[[operator_income, operator_cost]].groupby( KN.STOCK_ID.value).apply(lambda x: (x - x.mean()) / x.std()) # 回归取残差 data[func_name] = reg_input.groupby( KN.STOCK_ID.value, group_keys=False).apply(lambda x: cls._reg_rolling( x, operator_cost, operator_income, has_cons=True, win=quarter)) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Profit025(cls, data: pd.DataFrame, Surplus_Reserves: str = FBSN.Surplus_Reserves.value, Undistributed_Profit: str = FBSN.Undistributed_Profit.value, net_profit_in: str = FISN.Net_Pro_In.value, switch: bool = False): """ 股利支付率_TTM(DPR_TTM) = 每股股利/每股净利润 = (期末留存收益 - 期初留存收益) / 净利润 留存收益 = 盈余公积 + 未分配利润 :param data: :param Surplus_Reserves: :param Undistributed_Profit: :param net_profit_in: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data["RE"] = data[Surplus_Reserves] + data[Undistributed_Profit] data[func_name] = data['RE'] / data[net_profit_in] data = data.reset_index() if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Operate009(cls, data: pd.DataFrame, fixed_asset: str = FBSN.Fixed_Asset.value, operator_total_cost: str = FISN.Op_Total_Cost.value, quarter: int = 8, switch: bool = False): """ 产能利用率因子(OCFA) """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # 回归取残差 data[func_name] = data[[fixed_asset, operator_total_cost]].groupby( KN.STOCK_ID.value, group_keys=False).apply( lambda x: cls._reg_rolling(x, x_name=fixed_asset, y_name=operator_total_cost, has_cons=True, win=quarter)) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Profit032(cls, data: pd.DataFrame, net_profit_in: str = FISN.Net_Pro_In.value, total_asset: str = FBSN.Total_Asset.value, switch: bool = False): """ 总资产净利率(TTM,同比)(ROA_ttm_T) :param data: :param net_profit_in: :param total_asset: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['ROA_Q'] = data.groupby( KN.STOCK_ID.value, group_keys=False).apply( lambda x: x[net_profit_in].diff(1) / x[total_asset].shift(1)) data['ROA_Q'][np.isinf(data['ROA_Q'])] = np.nan data[func_name] = data['ROA_Q'].groupby(KN.STOCK_ID.value).diff(1) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data.reset_index(inplace=True) F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Solvency006(cls, data: pd.DataFrame, short_borrow: str = FBSN.ST_Borrow.value, short_bond_payable: str = FBSN.ST_Bond_Payable.value, long_borrow: str = FBSN.LT_Borrow.value, total_asset: str = FBSN.Total_Asset.value, switch: bool = False): """ 有息负债(Int_to_Asset) = 短期借款 + 短期应付债券 + 长期借款 :param data: :param short_borrow: :param short_bond_payable: :param long_borrow: :param total_asset: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[[short_borrow, short_bond_payable, long_borrow]].sum(skipna=True, axis=1) / data[total_asset] data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Solvency020(cls, data: pd.DataFrame, all_tax: str = FCFSN.All_Tax.value, quarter: int = 8, switch: bool = False): """ 各项税费变化率标准化(PTCF_qoq_Z) """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) # 部分会计科目若缺失填充零 data.fillna(0, inplace=True) PTCF_qoq = data[all_tax].groupby(KN.STOCK_ID.value).apply(lambda x: x.diff(1) / abs(x.shift(1))) PTCF_qoq_mean = PTCF_qoq.groupby(KN.STOCK_ID.value).apply(lambda x: x.rolling(quarter).mean()) PTCF_qoq_std = PTCF_qoq.groupby(KN.STOCK_ID.value).apply(lambda x: x.rolling(quarter).std()) data[func_name] = (PTCF_qoq - PTCF_qoq_mean) / PTCF_qoq_std # switch inf to nan data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Profit031(cls, data: pd.DataFrame, net_profit_in: str = FISN.Net_Pro_In.value, operator_income: str = FISN.Op_Income.value, switch: bool = False): """ 净利润率(同比)(NPM_T) = 本期净利润 / 本期主营业务收入 - 上期净利润 / 上期主营业务收入 :param data: :param net_profit_in: :param operator_income: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['NP'] = data[net_profit_in] / data[operator_income] data[np.isinf(data['NP'])] = 0 data[func_name] = data['NP'].groupby(KN.STOCK_ID.value).diff(1) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Quality010(cls, data: pd.DataFrame, cash_sales: str = FCFSN.Cash_From_Sales.value, operator_income: str = FISN.Op_Income.value, switch: bool = False): """ 收现比(CSR) = 销售商品提供劳务收到的现金 / 营业收入 :param data: :param cash_sales: :param operator_income: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[cash_sales] / data[operator_income] data[func_name][np.isinf(data[func_name])] = np.nan if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Operate010(cls, data: pd.DataFrame, operator_income: str = FISN.Op_Income.value, total_asset: str = FBSN.Total_Asset.value, switch: bool = False): """ 总资产周转率(同比)(TA_Turn_ttm_T) = 本期营业收入 / 本期平均资产总额 - 上期营业收入 / 上期平均资产总额 :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[total_asset] = data[total_asset].groupby( KN.STOCK_ID.value, group_keys=False).rolling(2, min_periods=1).mean() data["TA_turn_ttm"] = data[operator_income] / data[total_asset] data[func_name] = data["TA_turn_ttm"].groupby( KN.STOCK_ID.value).diff(1) if switch: data_fact = cls()._switch_freq(data_=data, name=func_name, limit=120) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Momentum027(cls, data: pd.DataFrame, close_price: str = PVN.CLOSE.value, n: int = 1) -> DataInfo: """ 收益率标准差(MTM_RankRet_std) """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data['ret'] = data[close_price].groupby(KN.STOCK_ID.value).pct_change() data[factor_name] = data['ret'].groupby(KN.TRADE_DATE.value, group_keys=False).rolling(n, min_periods=2).std(ddof=1) F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def Momentum021(cls, data: pd.DataFrame, price: str = PVN.CLOSE.value, n: int = 1): """ 最低价格时间因子(LT):1-index(Min(P, N))/L """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[factor_name] = data[price].groupby(KN.STOCK_ID.value, group_keys=False).rolling(n).apply( lambda x: 1 - (list(x).index(np.nanmin(x)) - 1) / len(x)) F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F
def Profit029(cls, data: pd.DataFrame, total_operator_income: str = FISN.Total_Op_Income.value, operator_profit: str = FISN.Op_Pro.value, switch: bool = False): """ 营业利润率(TTM)(OPM_TTM) = 营业利润 / 总营业收入 :param data: :param total_operator_income: :param operator_profit: :param switch: :return: """ func_name = sys._getframe().f_code.co_name data.set_index([SN.REPORT_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[func_name] = data[operator_profit] / data[total_operator_income] data[np.isinf(data[func_name])] = 0 if switch: data_fact = cls()._switch_freq(data_=data, name=func_name) else: data_fact = None data = data.reset_index() F = DataInfo() F.data_raw = data[[ SN.ANN_DATE.value, KN.STOCK_ID.value, SN.REPORT_DATE.value, func_name ]] F.data = data_fact F.data_type = data['type'][0] F.data_category = cls().__class__.__name__ F.data_name = func_name return F
def Momentum008(cls, data: pd.DataFrame, close_price: str = PVN.CLOSE.value, n: int = 1): """ 最低价格因子(LPTP):Max(P,N) / P """ factor_name = sys._getframe().f_code.co_name + f'_{n}days' data.set_index([KN.TRADE_DATE.value, KN.STOCK_ID.value], inplace=True) data.sort_index(inplace=True) data[factor_name] = data[close_price].groupby(KN.STOCK_ID.value, group_keys=False).apply( lambda x: x.rolling(n, min_periods=1).min() / x) F = DataInfo() F.data = data[factor_name] F.data_type = 'MTM' F.data_category = cls().__class__.__name__ F.data_name = factor_name return F