问题描述
解决方案
在 QMT 中获取股票的自由现金流(Free Cash Flow, FCF)数据进行选股,主要有两种方式:
- 使用多因子库(推荐): 直接调用 QMT 内置的计算好的因子数据,如
Derived_Data(衍生数据)表中的FCFE(股权自由现金流)或FCFF(企业自由现金流)。这种方式最简单,不需要自己处理财务报表的计算逻辑。 - 使用财务数据接口: 调用
get_financial_data获取原始的现金流量表数据(如经营活动现金流净额),然后自行计算。
下面我将提供一个完整的策略示例,使用第一种方式(多因子库),因为它更适合直接用于选股策略。我们将选取 股权自由现金流(FCFE) 最高的股票构建组合。
策略逻辑
- 股票池:沪深300成分股。
- 数据获取:使用
ContextInfo.get_factor_data获取Derived_Data.FCFE(股权自由现金流)。 - 选股逻辑:
- 剔除 FCFE 为空或负值的股票。
- 按照 FCFE 从大到小排序。
- 选取前 10 只股票。
- 交易执行:每月调仓一次,等权重买入。
策略代码
# -*- coding: gbk -*-
import pandas as pd
import time
def init(ContextInfo):
# 设置资金账号
ContextInfo.account_id = 'YOUR_ACCOUNT_ID' # 请替换为您的资金账号
ContextInfo.account_type = 'STOCK'
ContextInfo.set_account(ContextInfo.account_id)
# 策略参数
ContextInfo.holding_num = 10 # 持仓数量
ContextInfo.rebalance_period = '1mon' # 调仓周期:月度
ContextInfo.sector = '沪深300' # 股票池
# 设置定时器,用于控制调仓频率(这里配合handlebar使用,也可以用run_time)
# 在回测模式下,我们通常利用handlebar内的逻辑控制
print("策略初始化完成")
def handlebar(ContextInfo):
# 获取当前K线的时间戳
bar_index = ContextInfo.barpos
timetag = ContextInfo.get_bar_timetag(bar_index)
current_date_str = timetag_to_datetime(timetag, '%Y%m%d')
# 仅在回测模式下的每个月最后一个交易日,或者实盘的特定时间运行选股逻辑
# 这里为了演示简单,使用简单的周期判断逻辑,实际使用建议配合 ContextInfo.is_new_bar 等判断
# 如果不是当前周期的最后一根K线(对于日线回测),跳过
# 注意:get_factor_data 需要下载好对应时间段的因子数据
# 获取板块成分股
stock_list = ContextInfo.get_stock_list_in_sector(ContextInfo.sector, timetag)
if not stock_list:
print(f"{current_date_str} 未获取到成分股")
return
# --- 核心步骤:获取自由现金流数据 ---
# 字段说明:
# Derived_Data.FCFE: 股权自由现金流
# Derived_Data.FCFF: 企业自由现金流
# Per_Share_Analysis.ShareholderFCFPS: 每股股东自由现金流量
factor_fields = ['Derived_Data.FCFE']
# 获取因子数据
# 注意:get_factor_data 返回的数据结构取决于传入的股票数量和时间范围
# 这里传入多个股票,1个时间点,返回 DataFrame (index=股票代码, columns=字段)
factor_data = ContextInfo.get_factor_data(
factor_fields,
stock_list,
current_date_str,
current_date_str
)
if factor_data is None or factor_data.empty:
return
# --- 数据处理与选股 ---
# 1. 提取 FCFE 列
df_fcfe = factor_data['Derived_Data.FCFE']
# 2. 去除空值
df_fcfe = df_fcfe.dropna()
# 3. 过滤掉自由现金流为负的公司(可选,视策略而定)
df_fcfe = df_fcfe[df_fcfe > 0]
# 4. 排序:按自由现金流从大到小排序
df_fcfe = df_fcfe.sort_values(ascending=False)
# 5. 选取前 N 只
target_stocks = df_fcfe.head(ContextInfo.holding_num).index.tolist()
print(f"日期: {current_date_str}, 选股结果: {target_stocks}")
# --- 交易执行 (仅在回测或实盘信号触发时执行) ---
# 这里的逻辑是简单的全仓调仓
# 1. 获取当前持仓
positions = ContextInfo.get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
current_holdings = [obj.m_strInstrumentID for obj in positions]
# 2. 卖出不在目标列表中的股票
for stock in current_holdings:
if stock not in target_stocks:
order_target_value(stock, 0, ContextInfo, ContextInfo.account_id)
# 3. 买入目标股票
if len(target_stocks) > 0:
# 简单的资金分配:总资产 / 目标数量
# 注意:实际策略中应获取账户总资产 ContextInfo.capital (回测) 或 账户资金 (实盘)
# 这里演示使用 order_target_percent
target_weight = 1.0 / len(target_stocks)
for stock in target_stocks:
order_target_percent(stock, target_weight, ContextInfo, ContextInfo.account_id)
# 辅助函数:时间戳转字符串
def timetag_to_datetime(timetag, format_str):
import time
return time.strftime(format_str, time.localtime(timetag / 1000))
关键点说明
-
数据字段选择:
- 代码中使用了
Derived_Data.FCFE。这是 QMT 多因子库中预计算好的股权自由现金流。 - 如果你想使用企业自由现金流,请将字段改为
Derived_Data.FCFF。 - 如果你想使用每股数据,可以使用
Per_Share_Analysis.ShareholderFCFPS。
- 代码中使用了
-
数据补充:
- 在运行此策略之前,必须在 QMT 客户端界面中进行数据补充。
- 路径:系统 -> 数据管理 -> 补充数据 -> 多因子数据。
- 确保勾选了“股票因子_衍生数据”或全选,并下载了对应回测时间段的数据。
-
API 使用:
ContextInfo.get_factor_data(fieldList, stockList, startDate, endDate)是获取此类数据的核心 API。- 它返回的是
pandas的 DataFrame 或 Series,方便直接进行排序 (sort_values) 和筛选 (dropna)。
-
选股逻辑扩展:
- 单纯看 FCFE 的绝对值可能会偏向大盘股。
- 优化建议:你可以计算 自由现金流收益率 (FCF Yield)。方法是同时获取
Valuation_and_Market_Cap.MktValue(总市值),然后计算FCFE / MktValue,选取比率最高的股票,这样更能发掘被低估的优质现金流公司。
Q&A
Q: 如果我想自己用财务报表计算 FCF 怎么办?
A: 你可以使用 ContextInfo.get_financial_data 接口。
通常 FCF = 经营活动现金流净额 - 资本开支。
对应 QMT 字段为:
- 经营活动现金流净额:
ASHARECASHFLOW.net_cash_flows_oper_act - 资本开支(估算):
ASHARECASHFLOW.cash_pay_acq_const_fiolta(购建固定资产、无形资产和其他长期资产支付的现金)
Q: 为什么 get_factor_data 返回为空?
A: 通常有两个原因:
- 本地没有下载多因子数据(请去数据管理下载)。
- 传入的
stock_list为空或者startDate格式不正确(必须是 'YYYYMMDD' 字符串)。
Q: 这个策略可以直接实盘吗?
A: 代码包含了基本的交易逻辑,但实盘需要更严谨的风控(如停牌处理、涨跌停处理、滑点控制)。建议先在回测模式下验证效果,并确保资金账号配置正确。