Files
NewStock/main/factor/financial_factors.py

116 lines
3.4 KiB
Python
Raw Normal View History

2025-11-29 00:23:12 +08:00
"""
财务因子模块
包含基于股票截面的财务因子实现
"""
import numpy as np
import polars as pl
from main.factor.operator_framework import DateWiseFactor, StockWiseFactor
class CashflowToEVFactor(StockWiseFactor):
"""现金流-to-企业价值因子"""
def __init__(self):
super().__init__(
name="cashflow_to_ev",
parameters={},
required_factor_ids=["n_cashflow_act", "total_liab", "money_cap", "total_mv"]
)
def calc_factor(self, group_df: pl.DataFrame) -> pl.Series:
# 计算企业价值
total_mv = group_df["total_mv"]
total_liab = group_df["total_liab"]
money_cap = group_df["money_cap"]
# 企业价值 = 市值 + 负债合计 - 货币资金
enterprise_value = total_mv + total_liab - money_cap
# 计算现金流-to-EV比率
n_cashflow_act = group_df["n_cashflow_act"]
cashflow_ev_ratio = n_cashflow_act / (enterprise_value + 1e-8) # 避免除零
return cashflow_ev_ratio.alias(self.factor_id)
class BookToPriceFactor(StockWiseFactor):
"""账面价值-to-价格因子"""
def __init__(self):
super().__init__(
name="book_to_price",
parameters={},
required_factor_ids=["bps", "close"]
)
def calc_factor(self, group_df: pl.DataFrame) -> pl.Series:
# 计算账面价值-to-价格比率
bps = group_df["bps"]
close = group_df["close"]
book_to_price = bps / (close + 1e-8) # 避免除零
return book_to_price.alias(self.factor_id)
class DebtToEquityFactor(StockWiseFactor):
"""资产负债率因子"""
def __init__(self):
super().__init__(
name="debt_to_equity",
parameters={},
required_factor_ids=["total_liab", "equity"]
)
def calc_factor(self, group_df: pl.DataFrame) -> pl.Series:
# 计算资产负债率
total_liab = group_df["total_liab"]
equity = group_df["equity"]
debt_to_equity = total_liab / (equity + 1e-8) # 避免除零
return debt_to_equity.alias(self.factor_id)
class ProfitMarginFactor(StockWiseFactor):
"""净利润率因子"""
def __init__(self):
super().__init__(
name="profit_margin",
parameters={},
required_factor_ids=["net_profit", "revenue"]
)
def calc_factor(self, group_df: pl.DataFrame) -> pl.Series:
# 计算净利润率
net_profit = group_df["net_profit"]
revenue = group_df["revenue"]
profit_margin = net_profit / (revenue + 1e-8) # 避免除零
return profit_margin.alias(self.factor_id)
class BMFactor(StockWiseFactor):
"""账面市值比Book-to-Market, BM因子"""
def __init__(self):
super().__init__(
name="bm",
parameters={},
required_factor_ids=["total_hldr_eqy_exc_min_int", "total_mv"]
)
def calc_factor(self, group_df: pl.DataFrame) -> pl.Series:
book_value = group_df["total_hldr_eqy_exc_min_int"]
market_cap = group_df["total_mv"]
bm = book_value / (market_cap + 1e-8)
# 可选:过滤无效值(如负权益)
# bm = pl.when((book_value > 0) & (market_cap > 0)).then(bm).otherwise(None)
return bm.alias(self.factor_id)