股东变化趋势数据挖掘:用Python追踪筹码集中度与主力动向 IG50免费开源股票数据API接口
股东变化趋势数据挖掘:用Python追踪筹码集中度与主力动向
股东人数是判断筹码集中度的重要指标。股东人数减少意味着筹码在集中,可能有大户在吸筹;股东人数增加意味着筹码在分散,可能有大户在出货。我之前写了一套股东变化趋势分析工具,把全市场的股东户数数据系统地分析了一遍。
数据用的是股东变化趋势接口time/f10/gdbh/{股票代码},返回截止日期、股东户数、比上期变化情况。按截止日期倒序排列。配合十大股东接口time/f10/zygd/{股票代码}和十大流通股东接口time/f10/zygdlt/{股票代码},可以做更深入的分析。
import json
import os
import pandas as pd
import numpy as np
data_dir = "D:/stock_data"
def read_gdbh(dm):
file_path = os.path.join(data_dir, "time", "f10", "gdbh", dm)
if not os.path.exists(file_path):
return None
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
df = pd.DataFrame(data)
df.columns = ["jzrq", "gdhs", "bsqbh"]
df["jzrq"] = pd.to_datetime(df["jzrq"])
return df.sort_values("jzrq")
def read_zygd(dm):
file_path = os.path.join(data_dir, "time", "f10", "zygd", dm)
if not os.path.exists(file_path):
return None
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
return data
def read_zygdlt(dm):
file_path = os.path.join(data_dir, "time", "f10", "zygdlt", dm)
if not os.path.exists(file_path):
return None
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
return data
字段用简写,jzrq截止日期gdhs股东户数bsqbh比上期变化情况。十大股东和十大流通股东返回的是嵌套结构,包含截止日期、公告日期、股东总数、平均持股、十大股东列表等信息。
第一个分析:股东人数变化趋势。这是最基础的分析,看股东人数是在减少还是在增加。
def analyze_gdhs_trend(dm):
df = read_gdbh(dm)
if df is None or len(df) < 2:
return None
df["gdhs"] = pd.to_numeric(df["gdhs"], errors="coerce")
latest = df.iloc[-1]
prev = df.iloc[-2]
change_pct = (latest["gdhs"] - prev["gdhs"]) / prev["gdhs"]
recent_4 = df.tail(4)
trend = "下降" if recent_4["gdhs"].is_monotonic_decreasing else "上升" if recent_4["gdhs"].is_monotonic_increasing else "波动"
result = {
"dm": dm,
"latest_date": latest["jzrq"],
"latest_gdhs": latest["gdhs"],
"change_pct": change_pct,
"trend": trend
}
if change_pct < -0.15:
result["signal"] = "股东人数大幅减少,筹码集中"
result["score"] = 70
elif change_pct > 0.15:
result["signal"] = "股东人数大幅增加,筹码分散"
result["score"] = 35
else:
result["signal"] = "股东人数变化不大"
result["score"] = 50
return result
第二个分析:全市场筹码集中度扫描。遍历所有股票,找出股东人数连续减少的股票。
def scan_chip_concentration(top_n=30):
gplist_path = os.path.join(data_dir, "base", "gplist")
with open(gplist_path, "r", encoding="utf-8") as f:
gp_list = json.load(f)
results = []
for gp in gp_list:
dm = gp["股票代码"]
mc = gp["股票名称"]
df = read_gdbh(dm)
if df is None or len(df) < 3:
continue
df["gdhs"] = pd.to_numeric(df["gdhs"], errors="coerce")
recent_3 = df.tail(3)
if recent_3["gdhs"].is_monotonic_decreasing:
change_2q = (recent_3["gdhs"].iloc[-1] - recent_3["gdhs"].iloc[0]) / recent_3["gdhs"].iloc[0]
results.append({
"dm": dm,
"mc": mc,
"latest_gdhs": recent_3["gdhs"].iloc[-1],
"change_2q": change_2q
})
df_result = pd.DataFrame(results).sort_values("change_2q").head(top_n)
print("连续3期股东人数减少TOP{}:".format(top_n))
print(df_result.to_string(index=False))
return df_result
第三个分析:十大股东变动对比。对比相邻两个季度的十大股东名单,找出新进和退出的股东。
def compare_top10_change(dm):
data = read_zygd(dm)
if not data or len(data) < 2:
return None
latest = data[0]
prev = data[1]
latest_holders = set()
for holder in latest.get("ZygdSdgd", []):
latest_holders.add(holder.get("股东名称", ""))
prev_holders = set()
for holder in prev.get("ZygdSdgd", []):
prev_holders.add(holder.get("股东名称", ""))
new_in = latest_holders - prev_holders
exited = prev_holders - latest_holders
result = {
"dm": dm,
"latest_date": latest.get("截止日期", ""),
"prev_date": prev.get("截止日期", ""),
"new_holders": list(new_in),
"exited_holders": list(exited)
}
institution_keywords = ["基金", "社保", "保险", "信托", "QFII", "证金", "汇金", "资管"]
new_institutions = [h for h in new_in if any(kw in h for kw in institution_keywords)]
if new_institutions:
result["signal"] = "机构新进十大股东:{}".format("、".join(new_institutions))
result["score"] = 72
elif len(new_in) == 0 and len(exited) == 0:
result["signal"] = "十大股东无变动"
result["score"] = 55
else:
result["signal"] = "十大股东有变动但无机构新进"
result["score"] = 50
return result
第四个分析:结合股东人数变化和股价走势。股东人数减少+股价还没大涨的股票最值得关注。
def select_chip_concentration_strategy(top_n=20):
gplist_path = os.path.join(data_dir, "base", "gplist")
with open(gplist_path, "r", encoding="utf-8") as f:
gp_list = json.load(f)
candidates = []
for gp in gp_list:
dm = gp["股票代码"]
mc = gp["股票名称"]
df_gdbh = read_gdbh(dm)
if df_gdbh is None or len(df_gdbh) < 2:
continue
df_gdbh["gdhs"] = pd.to_numeric(df_gdbh["gdhs"], errors="coerce")
change_pct = (df_gdbh["gdhs"].iloc[-1] - df_gdbh["gdhs"].iloc[-2]) / df_gdbh["gdhs"].iloc[-2]
if change_pct > -0.10:
continue
kline = read_kline(dm, "day")
if kline is None or len(kline) < 60:
continue
recent_60 = kline.tail(60)
price_change = (recent_60["收盘价"].iloc[-1] - recent_60["收盘价"].iloc[0]) / recent_60["收盘价"].iloc[0]
if price_change > 0.10:
continue
candidates.append({
"dm": dm,
"mc": mc,
"gdhs_change": change_pct,
"price_change_60d": price_change
})
return pd.DataFrame(candidates).sort_values("gdhs_change").head(top_n)
策略逻辑是:股东人数减少超过10% + 60日涨幅不超过10%。前一个条件说明筹码在集中,后一个条件排除已经大涨的股票。这种"筹码集中但股价没动"的股票,后续上涨概率较高。
几个使用经验。第一,股东人数数据是季度披露的,有滞后性,只能做中长期参考。第二,股东人数减少要配合业绩看,业绩增长的筹码集中才有意义。第三,十大股东的季度变动比静态名单更有价值,要重点看机构新进。第四,基金持股接口time/f10/jjcg也可以配合使用,看基金持仓变化。
我用的数据来源是ig50的本地数据接口,股东变化趋势、十大股东、十大流通股东这些接口配合使用,能构建一个完整的筹码集中度分析系统。
接口说明:
-
time/f10/gdbh/{股票代码} - 股东变化趋势
本地路径:数据存放目录/time/f10/gdbh/{股票代码}
更新频率:每天15:30(更新完成约12小时)
数据格式:[{}…],按截止日期倒序
主要字段:截止日期(jzrq, yyyy-MM-dd)、股东户数(gdhs)、比上期变化情况(bsqbh) -
time/f10/zygd/{股票代码} - 十大股东
本地路径:数据存放目录/time/f10/zygd/{股票代码}
更新频率:每天15:30(更新完成约12小时)
数据格式:[{}…],按截止日期倒序
主要字段:截止日期、公告日期、股东说明、股东总数、平均持股、十大股东列表(含排名、股东名称、持股数量、持股比例、股本性质) -
time/f10/zygdlt/{股票代码} - 十大流通股东
本地路径:数据存放目录/time/f10/zygdlt/{股票代码}
更新频率:每天15:30(更新完成约12小时)
数据格式:[{}…],按公告日期倒序
主要字段:截止日期、公告日期、十大流通股东列表(含排名、股东名称、持股数量、持股比例、股本性质)
更多推荐
所有评论(0)