问题描述
似乎calc_factors不支持 EBITDA_1, 也不支持 fixed_assets_depreciation。
EBITDA本身是TTM过的吗?
解决方案
针对您在 JoinQuant 聚宽平台计算 EBITDA TTM 时遇到的问题,以下是详细的解答和计算方案:
1. EBITDA 本身是 TTM 过的吗?
不是。
根据 JoinQuant 因子库文档的定义,因子库中直接提供的 EBITDA 因子是报告期数据(即从年初到报告期末的累计值,例如一季报是1-3月,中报是1-6月),并没有经过 TTM(滚动十二个月)处理。
2. 为什么 calc_factors 不支持 EBITDA_1?
在 calc_factors 的 dependencies 中,使用 _1、_2 这种后缀来获取前几个季度的数据,仅适用于基础的单季度财务表字段(如 income 表、balance 表、cash_flow 表中的原生字段)。
EBITDA 属于 JoinQuant 因子库中的衍生因子,它是通过多个基础财务科目计算得出的,因此不支持直接通过加 _1 后缀来获取历史单季度数据。
3. 为什么不支持 fixed_assets_depreciation?
在 JoinQuant 的财务数据表中,固定资产折旧对应的准确字段名是 fixed_assets_depreciation(位于 cash_flow 现金流量表中)。如果您在 dependencies 中调用失败,可能是因为该字段在某些早期的单季度切片数据中存在缺失,或者拼写/表归属问题。在单季度数据中,现金流量表的拆分有时会因为财报披露规则导致部分科目为空(NaN)。
4. 如何正确计算 EBITDA TTM?
要计算 EBITDA TTM,最稳妥的方法是利用基础财务科目,通过自定义因子(继承 Factor 类)来手动计算。
EBITDA 的基础计算公式为:
EBITDA = 净利润 + 所得税费用 + 财务费用 + 折旧 + 摊销
为了计算 TTM,我们需要获取过去四个单季度的这些基础科目并求和。以下是使用 calc_factors 和自定义 Factor 的实现代码:
from jqfactor import Factor, calc_factors
import pandas as pd
class EBITDA_TTM(Factor):
# 设置因子名称
name = 'ebitda_ttm'
max_window = 1
# 依赖的基础单季度财务科目(包含当季及前三季)
# net_profit: 净利润 (income表)
# income_tax_expense: 所得税费用 (income表)
# financial_expense: 财务费用 (income表)
# fixed_assets_depreciation: 固定资产折旧、油气资产折耗、生产性生物资产折旧 (cash_flow表)
# intangible_assets_amortization: 无形资产摊销 (cash_flow表)
# long_term_deferred_expenses_amortization: 长期待摊费用摊销 (cash_flow表)
base_fields = [
'net_profit', 'income_tax_expense', 'financial_expense',
'fixed_assets_depreciation', 'intangible_assets_amortization',
'long_term_deferred_expenses_amortization'
]
# 生成包含 _1, _2, _3 后缀的依赖列表
dependencies = []
for field in base_fields:
dependencies.extend([field, f'{field}_1', f'{field}_2', f'{field}_3'])
def calc(self, data):
# 初始化 TTM 序列
ebitda_ttm = 0
# 遍历基础科目,将过去四个季度的数据相加
for field in self.base_fields:
# 将 NaN 填充为 0,防止相加后变成 NaN
q0 = data[field].fillna(0)
q1 = data[f'{field}_1'].fillna(0)
q2 = data[f'{field}_2'].fillna(0)
q3 = data[f'{field}_3'].fillna(0)
# 该科目的 TTM 值
field_ttm = q0 + q1 + q2 + q3
# 累加到 EBITDA TTM 中
ebitda_ttm += field_ttm
# 返回 Series
return ebitda_ttm.mean()
# 测试计算
securities = ['000001.XSHE', '600519.XSHG']
factors_result = calc_factors(
securities,
[EBITDA_TTM()],
start_date='2023-01-01',
end_date='2023-01-10',
use_real_price=False
)
print(factors_result['ebitda_ttm'].head())
替代方案:使用 get_history_fundamentals
如果您不是在单因子分析框架内,而是在普通的策略回测或研究中,可以直接使用 get_history_fundamentals 获取过去 4 个季度的财务数据进行计算,这样可以更灵活地处理缺失值:
from jqdata import *
def get_ebitda_ttm(security_list, stat_date):
# 查询需要的字段
q_fields = [
income.net_profit,
income.income_tax_expense,
income.financial_expense,
cash_flow.fixed_assets_depreciation,
cash_flow.intangible_assets_amortization,
cash_flow.long_term_deferred_expenses_amortization
]
# 获取过去4个季度的数据
df = get_history_fundamentals(security_list, fields=q_fields, stat_date=stat_date, count=4, interval='1q')
# 填充缺失值为0
df = df.fillna(0)
# 计算单季度的 EBITDA
df['ebitda_q'] = (df['net_profit'] + df['income_tax_expense'] + df['financial_expense'] +
df['fixed_assets_depreciation'] + df['intangible_assets_amortization'] +
df['long_term_deferred_expenses_amortization'])
# 按股票代码分组求和,得到 TTM
ebitda_ttm = df.groupby('code')['ebitda_q'].sum()
return ebitda_ttm
# 示例调用
print(get_ebitda_ttm(['000001.XSHE', '600519.XSHG'], '2023q3'))
总结:
由于 EBITDA 是衍生指标且非 TTM,建议通过提取 income 和 cash_flow 表中的基础单季度科目(如净利润、所得税、财务费用、折旧、摊销),利用 _1、_2、_3 后缀或 get_history_fundamentals 累加四个季度的数据,从而准确计算出 EBITDA TTM。