3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 QMT (Quantitative Trading Platform) 中,获取上市公司十大股东数据主要使用 ContextInfo.get_top10_share_holder 接口。
基于股东变化构建策略通常遵循**“筹码集中度”逻辑:如果前十大股东持股比例总和增加,通常意味着筹码趋于集中,主力资金可能在收集筹码,视为看多信号;反之,如果持股比例下降,意味着筹码分散,主力可能在派发,视为看空**信号。
以下是详细的 API 说明及完整的策略代码实现。
函数名: ContextInfo.get_top10_share_holder(stock_list, data_name, start_time, end_time)
['600519.SH']。'holder': 十大股东(包含流通和非流通)。'flow_holder': 十大流通股东。'20220101'。'20230101'。返回值:
返回 pandas.DataFrame(单股多季度或多股单季度)或 pandas.Panel(多股多季度)。
主要字段包括:holdRatio (持股比例), holdNum (持股数量), changReason (变动原因) 等。
本策略是一个低频趋势策略,逻辑如下:
600519.SH)。# -*- coding: gbk -*-
import pandas as pd
import time
def init(ContextInfo):
# 1. 设置策略基本参数
ContextInfo.stock = '600519.SH' # 标的股票:贵州茅台
ContextInfo.account_id = '600000248' # 请替换为您的真实资金账号
ContextInfo.set_account(ContextInfo.account_id)
# 设置股票池
ContextInfo.set_universe([ContextInfo.stock])
# 2. 策略控制变量
ContextInfo.check_interval = 5 # 每隔5天检查一次数据,减少运算量
ContextInfo.days_counter = 0
def handlebar(ContextInfo):
# 跳过非交易日或未完成的K线
if not ContextInfo.is_last_bar():
return
# 限制检查频率
ContextInfo.days_counter += 1
if ContextInfo.days_counter < ContextInfo.check_interval:
return
ContextInfo.days_counter = 0
# 1. 获取当前时间
current_time = ContextInfo.get_bar_timetag(ContextInfo.barpos)
# 将时间戳转换为字符串格式 YYYYMMDD
end_date = timetag_to_datetime(current_time, '%Y%m%d')
# 设置开始时间为一年前,确保能取到至少两期财报数据
start_date = timetag_to_datetime(current_time - 365 * 24 * 3600 * 1000, '%Y%m%d')
# 2. 获取十大流通股东数据
# data_name 使用 'flow_holder' 获取流通股东,也可以用 'holder' 获取全部股东
try:
df = ContextInfo.get_top10_share_holder(
[ContextInfo.stock],
'flow_holder',
start_date,
end_date
)
except Exception as e:
print(f"获取数据异常: {e}")
return
if df is None or df.empty:
return
# 3. 数据处理
# 返回的 df index 通常是日期,columns 是字段名
# 我们需要按日期分组,计算持股比例(holdRatio)的总和
# 确保索引是日期格式以便排序
df.index = pd.to_datetime(df.index)
# 按日期分组求和,计算每一期十大股东的持股比例总和
# holdRatio 单位通常是百分比
concentration_series = df.groupby(df.index)['holdRatio'].sum().sort_index()
# 确保至少有两期数据进行比较
if len(concentration_series) < 2:
print("历史财报数据不足,无法比较")
return
# 获取最近两期的数据
last_ratio = concentration_series.iloc[-1] # 最新一期
prev_ratio = concentration_series.iloc[-2] # 上一期
report_date = concentration_series.index[-1].strftime('%Y-%m-%d')
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
current_holding = 0
for pos in positions:
if pos.m_strInstrumentID == ContextInfo.stock:
current_holding = pos.m_nVolume
break
# 4. 交易逻辑
# 信号:筹码集中(最新比例 > 上期比例) -> 买入
if last_ratio > prev_ratio:
if current_holding == 0:
print(f"[{end_date}] 筹码集中信号: 最新({last_ratio:.2f}%) > 上期({prev_ratio:.2f}%)。报告期:{report_date}。执行买入。")
# 全仓买入 (使用 order_target_percent 需要在回测设置中设置初始资金)
order_target_percent(ContextInfo.stock, 0.9, ContextInfo, ContextInfo.account_id)
else:
# 已经是持仓状态,继续持有
pass
# 信号:筹码分散(最新比例 < 上期比例) -> 卖出
elif last_ratio < prev_ratio:
if current_holding > 0:
print(f"[{end_date}] 筹码分散信号: 最新({last_ratio:.2f}%) < 上期({prev_ratio:.2f}%)。报告期:{report_date}。执行卖出。")
# 清仓
order_target_percent(ContextInfo.stock, 0, ContextInfo, ContextInfo.account_id)
else:
print(f"[{end_date}] 筹码无变化。")
get_top10_share_holder 需要足够长的时间窗口(代码中设置为过去365天),因为财报是季度发布的。如果时间窗口太短,可能只获取到一期数据,无法计算变化。df.groupby(df.index)['holdRatio'].sum() 将同一日期的10位股东持股比例加总,得到当期的“集中度”。order_target_percent 函数。
0.9 代表调整仓位至总资产的 90%(买入)。0 代表调整仓位至 0%(清仓卖出)。timetag_to_datetime 将 QMT 的毫秒时间戳转换为 API 所需的 'YYYYMMDD' 字符串格式。Q: 如何区分“十大股东”和“十大流通股东”?
A: 在 get_top10_share_holder 函数的第二个参数中设置。传入 'holder' 获取前十大股东(包含限售股),传入 'flow_holder' 获取前十大流通股东。通常二级市场交易更关注流通股东的变化。
Q: 这个策略适合高频交易吗?
A: 不适合。股东数据每季度才更新一次(年报、一季报、半年报、三季报),信号频率极低,属于中长线基本面/资金面策略。
Q: 如果我想跟踪特定机构(如“证金公司”)的持仓怎么办?
A: API 返回的 DataFrame 中包含 holdName(股东名称)字段。你可以在代码中遍历数据,筛选 holdName 包含特定关键字的行,然后单独计算其持股变化。