问题描述
解决方案
根据流动比率(Current Ratio)选股是一种基于基本面分析的策略。流动比率衡量的是企业偿还短期债务的能力,计算公式为:流动资产 / 流动负债。通常认为,流动比率越高,企业的短期偿债能力越强。
在 QMT 中,我们可以利用 多因子数据接口 (ContextInfo.get_factor_data) 来获取该指标。
策略逻辑
- 股票池:设定为沪深300成分股(示例)。
- 选股指标:
Solvency_and_Capital_Structure.CurrentRatio(偿债能力和资本结构 - 流动比率)。 - 筛选条件:选取流动比率大于 2.0 的股票(数值可调整)。
- 交易逻辑:
- 每月第一个交易日进行调仓。
- 卖出不在新名单中的持仓股。
- 买入满足条件的股票,资金等权分配。
QMT 策略代码实现
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
def init(ContextInfo):
# 1. 设置策略参数
ContextInfo.target_ratio = 2.0 # 流动比率阈值
ContextInfo.holding_num = 20 # 最大持仓数量(可选,防止资金过于分散)
# 2. 设置股票池 (这里以沪深300为例)
ContextInfo.index_code = '000300.SH'
ContextInfo.set_universe(ContextInfo.get_sector(ContextInfo.index_code))
# 3. 设置账号 (回测模式下会自动使用虚拟账号,实盘需替换为真实账号)
ContextInfo.account_id = 'test_account'
ContextInfo.account_type = 'STOCK'
ContextInfo.set_account(ContextInfo.account_id)
# 4. 初始化全局变量
ContextInfo.rebalance_period = 'monthly' # 调仓周期
ContextInfo.last_rebalance_month = -1
def handlebar(ContextInfo):
# 获取当前K线的时间
bar_index = ContextInfo.barpos
current_time = ContextInfo.get_bar_timetag(bar_index)
current_date_str = timetag_to_datetime(current_time, '%Y%m%d')
current_month = int(current_date_str[4:6])
# -------------------------------------------------------
# 调仓逻辑控制:每月第一个交易日调仓
# -------------------------------------------------------
if ContextInfo.last_rebalance_month == current_month:
return # 本月已调仓,跳过
# 更新调仓月份标记
ContextInfo.last_rebalance_month = current_month
print(f'=== 开始调仓: {current_date_str} ===')
# -------------------------------------------------------
# 1. 获取数据
# -------------------------------------------------------
stock_list = ContextInfo.get_universe()
# 因子名称:偿债能力和资本结构 - 流动比率
factor_name = 'Solvency_and_Capital_Structure.CurrentRatio'
# 获取因子数据
# 注意:get_factor_data 返回的数据结构取决于传入的股票和时间数量
# 传入多只股票、单日时间,返回 DataFrame (index=股票代码, columns=因子名)
factor_data = ContextInfo.get_factor_data(
[factor_name],
stock_list,
current_date_str,
current_date_str
)
# 数据清洗:去除空值
if factor_data.empty:
print("未获取到因子数据")
return
# -------------------------------------------------------
# 2. 选股逻辑
# -------------------------------------------------------
# 筛选流动比率大于阈值的股票
# 注意:factor_data 是一个 DataFrame,列名为因子全名
if factor_name not in factor_data.columns:
print(f"数据中缺少因子列: {factor_name}")
return
# 过滤掉 NaN 值
valid_data = factor_data.dropna(subset=[factor_name])
# 筛选大于阈值的股票
selected_df = valid_data[valid_data[factor_name] > ContextInfo.target_ratio]
# (可选) 排序:例如按流动比率从大到小排序,取前N只
selected_df = selected_df.sort_values(by=factor_name, ascending=False)
target_stocks = selected_df.head(ContextInfo.holding_num).index.tolist()
print(f"选出股票数量: {len(target_stocks)}")
# -------------------------------------------------------
# 3. 交易执行
# -------------------------------------------------------
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.account_id, ContextInfo.account_type, 'POSITION')
holding_stocks = [obj.m_strInstrumentID for obj in positions if obj.m_nVolume > 0]
# 卖出不在目标列表中的股票
for stock in holding_stocks:
if stock not in target_stocks:
order_target_value(stock, 0, ContextInfo, ContextInfo.account_id)
print(f"卖出: {stock}")
# 买入目标股票
if len(target_stocks) > 0:
# 简单的等权分配资金 (注意:这里使用 order_target_percent 需要在回测设置中设置初始资金)
# 也可以使用 order_target_value 根据总资产计算
weight = 1.0 / len(target_stocks)
for stock in target_stocks:
order_target_percent(stock, weight, ContextInfo, ContextInfo.account_id)
print(f"买入/调仓: {stock}, 目标权重: {weight:.2%}")
代码关键点解析
-
数据接口 (
get_factor_data):- 我们使用了
Solvency_and_Capital_Structure.CurrentRatio这个字段。 - 该接口返回的是
pandas.DataFrame,索引是股票代码,列名是因子名称。 - 注意:因子数据通常有滞后性(基于财报发布日期),QMT 的因子库会自动处理这点,获取的是当时可获得的最新财报数据。
- 我们使用了
-
时间控制:
- 基本面数据变化频率较低(季度更新),因此不需要每日频繁交易。
- 代码中通过
current_month和last_rebalance_month的对比,实现了月度调仓。
-
交易函数:
- 使用了
order_target_percent(目标比例下单)。这在调仓时非常方便,它会自动计算需要买入或卖出的股数,将仓位调整到指定的权重(例如 5%)。 - 注意:在实盘中使用
order_target_percent时,请确保ContextInfo能正确获取到账户的总资产数据,否则建议改用order_target_value或order_lots。
- 使用了
-
容错处理:
- 增加了
.dropna()处理,防止因为某些股票停牌或未发布财报导致数据为空(NaN)而报错。
- 增加了
常见问题 Q&A
Q: 如何查看还有哪些财务因子可以使用?
A: 在 QMT 的帮助文档或“数据管理”界面中,查看“多因子数据”部分。例如,速动比率是 Solvency_and_Capital_Structure.QuickRatio,资产负债率是 Solvency_and_Capital_Structure.DebtsAssetRatio。
Q: 为什么回测时没有交易?
A:
- 请检查回测时间段内是否有财报数据(因子数据需要下载补充)。
- 检查
ContextInfo.index_code设置的指数成分股在回测区间内是否存在。 - 检查
ContextInfo.target_ratio阈值是否设置过高,导致选不出股票。
Q: 如何结合其他指标(如市盈率 PE)?
A: 可以在 get_factor_data 的第一个参数列表中添加字段,例如 ['Solvency_and_Capital_Structure.CurrentRatio', 'Valuation_and_Market_Cap.PE'],然后在获取到的 DataFrame 中增加额外的筛选逻辑即可(例如 df[(df['...CurrentRatio'] > 2) & (df['...PE'] < 20)])。