龙虎榜数据深度挖掘用Python追踪机构席位与营业部交易行为
龙虎榜数据深度挖掘:用Python追踪机构席位与营业部交易行为
大概是在2021年的时候,我开始关注龙虎榜数据。那时候市场上有个说法叫"龙虎榜选股,胜率翻倍",虽然有点夸张,但龙虎榜确实能反映出市场上最活跃资金的动向。后来我花了几个月时间,把龙虎榜数据系统地研究了一遍,还写了一套分析工具。这篇文章就来聊聊我是怎么用Python分析龙虎榜数据,追踪机构席位和营业部交易行为的。
先说一下龙虎榜数据有什么用。简单来说,龙虎榜是交易所每天公布的异动股票名单,包括当日涨跌幅偏离值达到7%的、换手率达到20%的、连续三个交易日涨幅偏离值累计达到20%的等等。每只上榜股票都会公布买入金额前五和卖出金额前五的营业部席位。通过分析这些席位的买卖行为,我们可以大致判断出市场上的主力资金在关注哪些股票,哪些营业部是"涨停板敢死队",哪些机构席位在默默布局。
我主要用到四块数据:第一块是每日龙虎榜详情,也就是每天有哪些股票上榜,对应的买卖席位;第二块是机构席位追踪,统计近几日机构席位在哪些股票上有交易;第三块是营业部上榜统计,看看哪些营业部最活跃;第四块是机构席位成交明细,近五个交易日机构席位的具体买卖情况。
先从数据读取开始。龙虎榜数据都在all目录下,每日详情是all/ld,机构席位追踪是all/jgzz/{n},营业部统计是all/yyb/{n},机构成交明细是all/jgcj。这里的n表示近n日,可以取5、10、30、60。
import json
import os
import pandas as pd
import numpy as np
from collections import defaultdict
import datetime
data_dir = "D:/stock_data"
def read_ld(date_str=None):
file_path = os.path.join(data_dir, "all", "ld")
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_jgzz(n=30):
file_path = os.path.join(data_dir, "all", "jgzz", str(n))
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 = ["dm", "mc", "ljmre", "mrCs", "ljmce", "mcCs", "je"]
return df
def read_yyb(n=30):
file_path = os.path.join(data_dir, "all", "yyb", str(n))
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 = ["yybMc", "sbCs", "ljmre", "mrXw", "ljmce", "mcXw", "mrQsgp"]
return df
def read_jgcj():
file_path = os.path.join(data_dir, "all", "jgcj")
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 = ["dm", "mc", "jyrq", "jgMre", "jgMce", "lx"]
return df
字段名我还是用了简写,dm是股票代码,mc是名称,ljmre是累积买入额,mrCs是买入次数,ljmce是累积卖出额,mcCs是卖出次数,je是净额。yyb相关的字段,yybMc是营业部名称,sbCs是上榜次数,mrXw是买入席位,mcXw是卖出席位,mrQsgp是买入前三股票。jg相关的,jyrq是交易日期,jgMre是机构席位买入额,jgMce是机构席位卖出额,lx是上榜类型。
数据读进来之后,我会先做一个整体的概览分析。比如,看看最近一个月机构席位主要在买哪些股票,哪些营业部最活跃,机构席位的净买入额排名等等。这些统计可以帮我们快速把握市场主力资金的动向。
def analyze_jgzz(df_jgzz, top_n=20):
if df_jgzz is None or len(df_jgzz) == 0:
return None
df_sorted = df_jgzz.sort_values("je", ascending=False)
top_buy = df_sorted.head(top_n)[["dm", "mc", "ljmre", "ljmce", "je", "mrCs", "mcCs"]]
top_sell = df_sorted.tail(top_n)[["dm", "mc", "ljmre", "ljmce", "je", "mrCs", "mcCs"]]
print("机构席位净买入TOP{}:".format(top_n))
print(top_buy.to_string(index=False))
print("\n机构席位净卖出TOP{}:".format(top_n))
print(top_sell.to_string(index=False))
return top_buy, top_sell
机构席位追踪数据能告诉我们近一段时间机构在买什么卖什么,但光看这个还不够。因为机构席位的交易有时候是建仓,有时候是出货,单凭一个净额很难判断。所以我会结合机构席位成交明细来看,也就是近五个交易日每天的买卖情况。如果机构连续几天都在净买入某只股票,那信号就比较强了。
def analyze_jgcj(df_jgcj, dm):
if df_jgcj is None or len(df_jgcj) == 0:
return None
df_stock = df_jgcj[df_jgcj["dm"] == dm].copy()
if len(df_stock) == 0:
return None
df_stock["je"] = df_stock["jgMre"] - df_stock["jgMce"]
df_stock = df_stock.sort_values("jyrq")
print("股票{}({})近期机构席位成交明细:".format(df_stock["mc"].iloc[0], dm))
print(df_stock[["jyrq", "jgMre", "jgMce", "je", "lx"]].to_string(index=False))
total_mre = df_stock["jgMre"].sum()
total_mce = df_stock["jgMce"].sum()
total_je = total_mre - total_mce
print("\n近5日机构买入合计:{}万,卖出合计:{}万,净额:{}万".format(total_mre, total_mce, total_je))
return df_stock
接下来是营业部分析。龙虎榜上的营业部大致可以分几类:一类是机构专用席位,这类是基金、保险、社保这些机构在交易;一类是知名游资席位,比如东方财富证券拉萨团结路、中信证券上海溧阳路这些,它们的特点是操作频繁、擅长打板;还有一类是普通营业部,偶尔上榜。
我会先统计近一个月上榜次数最多的营业部,看看哪些最活跃。然后看这些营业部的买入额和卖出额,如果一个营业部的上榜次数多、净买入额也大,说明它比较乐观。反过来,如果上榜次数多但净卖出额大,可能就偏谨慎了。
def analyze_yyb(df_yyb, top_n=30):
if df_yyb is None or len(df_yyb) == 0:
return None
df_yyb["je"] = df_yyb["ljmre"] - df_yyb["ljmce"]
df_sorted = df_yyb.sort_values("sbCs", ascending=False)
print("营业部上榜次数TOP{}:".format(top_n))
print(df_sorted.head(top_n)[["yybMc", "sbCs", "ljmre", "ljmce", "je"]].to_string(index=False))
df_je_sorted = df_yyb.sort_values("je", ascending=False)
print("\n营业部净买入额TOP{}:".format(top_n))
print(df_je_sorted.head(top_n)[["yybMc", "sbCs", "ljmre", "ljmce", "je"]].to_string(index=False))
return df_sorted
在营业部分析中,我发现一个很有意思的现象:有些营业部的操作风格非常鲜明。比如东方财富证券拉萨团结路,几乎天天上榜,买卖的都是市场上最热门的题材股,而且换手率极高,典型的短线游资风格。而有些机构专用席位,上榜次数不多,但每次买卖的金额都很大,而且持有周期相对较长。
为了量化营业部的风格,我写了一个简单的分类函数,根据营业部的上榜次数、平均买卖金额、买卖的股票类型等特征,把营业部分成机构型、游资型、散户型三类。当然这个分类比较粗糙,只是一个大致的判断。
def classify_yyb_style(row):
sbCs = row["sbCs"]
avg_mre = row["ljmre"] / sbCs if sbCs > 0 else 0
if "机构专用" in row["yybMc"]:
return "机构型"
elif sbCs >= 20 and avg_mre < 2000:
return "游资型"
else:
return "普通型"
有了营业部风格分类之后,就可以做更有针对性的分析了。比如,我会专门跟踪机构型席位的动向,因为机构的研究能力相对更强,它们重仓买入的股票往往有基本面支撑。而游资型席位的动向,可以帮助我们判断市场的热点在哪里,哪些题材正在被炒作。
每日龙虎榜详情的分析是另一个重点。每天的龙虎榜数据包含了多种异动类型,比如涨跌幅偏离值、换手率、振幅等等。我会把每天上榜的股票按类型分类,然后看每类的上榜股票有什么共同特点。
def analyze_ld_detail(ld_data):
if ld_data is None or len(ld_data) == 0:
return None
today_data = ld_data[0] if isinstance(ld_data, list) else ld_data
date_str = today_data.get("日期", "")
types = {
"zpl7": "涨幅偏离值达7%",
"dpl7": "跌幅偏离值达7%",
"h20": "换手率达20%",
"z20": "连续三日涨幅偏离值累计达20%",
"zf15": "振幅值达15%",
"df15": "连续三日跌幅偏离值累计达20%"
}
all_stocks = []
for key, name in types.items():
stocks = today_data.get(key, [])
for stk in stocks:
stk_info = {
"dm": stk.get("股票代码", ""),
"mc": stk.get("股票名称", ""),
"spj": stk.get("收盘价(元)", 0),
"dyz": stk.get("对应值(%)", 0),
"cjl": stk.get("成交量(万股)", 0),
"cje": stk.get("成交额(万元)", 0),
"lx": name
}
all_stocks.append(stk_info)
df = pd.DataFrame(all_stocks)
print("日期:{},今日上榜股票共{}只".format(date_str, len(df)))
print("\n上榜类型分布:")
print(df["lx"].value_counts())
return df
把这些分析串起来,我每天盘后会做这样一个流程:先看今日龙虎榜详情,了解哪些股票异动、是什么类型的异动;然后看机构席位成交明细,看看机构在这些异动股票上的买卖情况;接着看机构席位追踪和营业部统计,掌握一段时间内的资金流向趋势;最后把这些信息综合起来,筛选出值得重点关注的股票。
我还写了一个简单的选股策略,基于龙虎榜数据。策略逻辑是这样的:首先,从近一个月的机构席位追踪数据中,选出机构净买入额排名前50的股票;然后,从这些股票中剔除ST股和近一个月涨幅超过50%的(避免追高);接着,结合营业部数据,如果有知名游资席位也在买入的话加分;最后,选出综合得分最高的10只股票,作为观察池。
def lhb_select_strategy(df_jgzz, df_yyb, df_gp, top_n=10):
df_jg = df_jgzz.copy()
df_merged = df_jg.merge(df_gp[["dm", "mc", "isSt"]], on=["dm", "mc"], how="left")
df_merged = df_merged[df_merged["isSt"] == 0]
df_merged = df_merged.sort_values("je", ascending=False)
candidates = df_merged.head(50).copy()
yyb_hot_stocks = set()
for _, row in df_yyb.head(20).iterrows():
if pd.notna(row["mrQsgp"]):
for stk in row["mrQsgp"].split(","):
yyb_hot_stocks.add(stk)
candidates["yyb_hot"] = candidates["mc"].apply(lambda x: 1 if x in yyb_hot_stocks else 0)
candidates["score"] = candidates["je"].rank(pct=True) * 0.7 + candidates["yyb_hot"] * 0.3
selected = candidates.sort_values("score", ascending=False).head(top_n)
print("龙虎榜策略选股结果(TOP{}):".format(top_n))
print(selected[["dm", "mc", "je", "yyb_hot", "score"]].to_string(index=False))
return selected
当然,这个策略只是一个基础版本,实际用的时候还要结合其他因素。比如,我会再看一下选出的股票的基本面情况,如果基本面太差,即使龙虎榜数据好看也不会买。还有就是技术面,看看股价是不是在上升趋势中,成交量有没有配合放大。
实际使用下来,龙虎榜数据分析有几个地方特别值得注意。第一,机构席位的数据比营业部数据更有参考价值,因为机构的决策更理性,研究也更深入。第二,不要只看单日的龙虎榜,要结合一段时间的趋势来看,连续多日的机构净买入信号更强。第三,龙虎榜是滞后数据,等你看到的时候股价可能已经涨了一截,所以不能盲目追涨,要结合估值和基本面来判断。
还有一个坑我踩过,就是有些营业部是"一日游"风格,今天买明天卖,如果你跟着买很容易被套。所以我后来加了一个过滤条件,就是看营业部的平均持有周期,如果持有周期太短,即使它在买入,我也不会轻易跟进。
总的来说,龙虎榜数据分析是一个非常实用的工具。它不能保证你每次都赚钱,但可以帮你更清晰地理解市场资金的动向,让你的投资决策多一个维度的参考。如果你也对龙虎榜感兴趣,建议先从跟踪机构席位开始,相对来说确定性更高一些。
我用的数据来源是ig50的本地数据接口,数据更新及时,字段也很完整,做二次开发很方便。感兴趣的朋友可以自行了解。
接口说明:
-
all/ld - 每日龙虎榜详情
本地路径:数据存放目录/all/ld
主要字段:日期、涨幅偏离值达7%的证券(zpl7)、跌幅偏离值达7%的证券(dpl7)、换手率达20%的证券(h20)、连续三日涨幅偏离值累计达20%的证券(z20)、振幅值达15%的证券(zf15)等
每只证券包含:股票代码、股票名称、收盘价(元)、对应值(%)、成交量(万股)、成交额(万元) -
all/jgzz/{近n日} - 机构席位追踪
本地路径:数据存放目录/all/jgzz/{近n日}(n可取5、10、30、60)
主要字段:股票代码(dm)、股票名称(mc)、累积买入额(万)(ljmre)、买入次数(mrCs)、累积卖出额(万)(ljmce)、卖出次数(mcCs)、净额(万)(je) -
all/yyb/{近n日} - 营业部上榜统计
本地路径:数据存放目录/all/yyb/{近n日}(n可取5、10、30、60)
主要字段:营业部名称(yybMc)、上榜次数(sbCs)、累积获取额(万)(ljmre)、买入席位(mrXw)、累积卖出额(万)(ljmce)、卖出席位(mcXw)、买入前三股票(mrQsgp) -
all/jgcj - 机构席位成交明细
本地路径:数据存放目录/all/jgcj
主要字段:股票代码(dm)、股票名称(mc)、交易日期(jyrq)、机构席位买入额(万)(jgMre)、机构席位卖出额(万)(jgMce)、类型(lx)
资料参考:ig50
更多推荐



所有评论(0)