大宗交易数据追踪系统:用Python挖掘折溢价信号与机构意图
大宗交易是A股市场大额股权转让的专用通道,每笔交易都透露着大资金的真实意图。但大部分散户对大宗交易的理解停留在"大股东在卖"的层面,忽略了其中丰富的信号。去年我搭建了一个大宗交易数据追踪系统,用Python从大单成交数据中挖掘折溢价信号和机构意图。这篇文章分享系统的核心设计和实现。
本地数据引擎提供了大单成交数据,路径是time/real/trace/bigdeal/{dm},包含了每笔大单的成交时间、价格、数量和方向。实时行情数据在time/real/{dm},可以获取当日收盘价用于计算折溢价率。历史K线数据在time/history/trade/{dm}/day,用于分析大宗交易后的股价走势。
import json
import os
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
data_dir = "D:/ig50_data"
def read_bigdeal(dm):
file_path = os.path.join(data_dir, "time", "real", "trace", "bigdeal", dm)
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
df = pd.DataFrame(data)
df.columns = ["dm", "mc", "cjsj", "cjjg", "cjl", "jyzd"]
df["cjsj"] = pd.to_datetime(df["cjsj"])
df["cje"] = df["cjjg"] * df["cjl"]
return df
def read_realtime(dm):
file_path = os.path.join(data_dir, "time", "real", dm)
with open(file_path, "r", encoding="utf-8") as f:
return json.load(f)
def read_daily_kline(dm):
file_path = os.path.join(data_dir, "time", "history", "trade", dm, "day")
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
df = pd.DataFrame(data)
df.columns = ["dm", "cjsj", "cjjg", "cjl", "cje", "zf"]
df["cjsj"] = pd.to_datetime(df["cjsj"])
return df
字段方面,dm是股票代码,mc是股票名称,cjsj是成交时间,cjjg是成交价格,cjl是成交量,jyzd是交易方向(0中性/1买入/2卖出),cje是成交额。
系统的第一个分析模块是折溢价率计算。大宗交易的成交价通常偏离当日收盘价,折价说明买方要求补偿,溢价说明买方急于建仓。
def calc_premium_discount(dm):
df_bigdeal = read_bigdeal(dm)
if len(df_bigdeal) == 0:
return None
realtime = read_realtime(dm)
close_price = realtime.get("cjjg", 0)
if close_price == 0:
return None
results = []
for _, row in df_bigdeal.iterrows():
deal_price = row["cjjg"]
discount = (deal_price - close_price) / close_price * 100
results.append({
"cjsj": row["cjsj"],
"deal_price": deal_price,
"close_price": close_price,
"discount_pct": discount,
"amount": row["cje"],
"direction": row["jyzd"],
"type": "溢价" if discount > 0 else "折价" if discount < -0.5 else "平价"
})
return pd.DataFrame(results)
def classify_bigdeal(dm):
df = calc_premium_discount(dm)
if df is None or len(df) == 0:
return None
total_amount = df["amount"].sum()
avg_discount = df["discount_pct"].mean()
has_premium = (df["discount_pct"] > 0).any()
has_large_discount = (df["discount_pct"] < -10).any()
if has_premium:
signal = "强烈看多"
score = 80
elif avg_discount > -2:
signal = "中性偏多"
score = 55
elif has_large_discount:
signal = "看空"
score = 25
else:
signal = "中性"
score = 50
return {
"total_amount": total_amount,
"avg_discount": avg_discount,
"signal": signal,
"score": score,
"deal_count": len(df)
}
第二个分析模块是大宗交易频率追踪。如果一只股票在短时间内出现多笔大宗交易,说明大额筹码在转移。
def analyze_bigdeal_frequency(dm, lookback_days=30):
df_bigdeal = read_bigdeal(dm)
if len(df_bigdeal) == 0:
return None
cutoff = datetime.now() - timedelta(days=lookback_days)
recent = df_bigdeal[df_bigdeal["cjsj"] >= cutoff]
if len(recent) == 0:
return None
daily_deals = recent.groupby(recent["cjsj"].dt.date).agg({
"cje": "sum",
"cjsj": "count"
}).rename(columns={"cjsj": "deal_count"})
consecutive_days = 0
max_consecutive = 0
dates = sorted(daily_deals.index)
for i in range(len(dates) - 1):
if (dates[i + 1] - dates[i]).days <= 3:
consecutive_days += 1
max_consecutive = max(max_consecutive, consecutive_days)
else:
consecutive_days = 0
return {
"total_deals": len(recent),
"total_amount": recent["cje"].sum(),
"avg_daily_deals": len(recent) / lookback_days,
"max_consecutive_days": max_consecutive,
"frequency_signal": "高频" if len(recent) > 5 else "正常"
}
第三个分析模块是大宗交易后走势分析。统计大宗交易发生后股价的表现,验证信号的有效性。
def analyze_post_bigdeal_performance(dm, lookback_days=60):
df_bigdeal = read_bigdeal(dm)
df_kline = read_daily_kline(dm)
if len(df_bigdeal) == 0 or len(df_kline) == 0:
return None
cutoff = datetime.now() - timedelta(days=lookback_days)
recent_deals = df_bigdeal[df_bigdeal["cjsj"] >= cutoff]
results = []
for _, deal in recent_deals.iterrows():
deal_date = deal["cjsj"]
deal_price = deal["cjjg"]
post_kline = df_kline[df_kline["cjsj"] > deal_date].head(5)
if len(post_kline) < 5:
continue
price_5d = post_kline["cjjg"].iloc[-1]
return_5d = (price_5d - deal_price) / deal_price * 100
max_price = post_kline["cjjg"].max()
min_price = post_kline["cjjg"].min()
results.append({
"deal_date": deal_date,
"deal_price": deal_price,
"price_5d": price_5d,
"return_5d": return_5d,
"max_return": (max_price - deal_price) / deal_price * 100,
"min_return": (min_price - deal_price) / deal_price * 100
})
if not results:
return None
df_result = pd.DataFrame(results)
return {
"avg_return_5d": df_result["return_5d"].mean(),
"win_rate": (df_result["return_5d"] > 0).mean() * 100,
"avg_max_return": df_result["max_return"].mean(),
"avg_min_return": df_result["min_return"].mean()
}
第四个分析模块是大单方向汇总。通过jyzd字段判断大单是买入还是卖出,计算净买入金额。
def summarize_bigdeal_direction(dm):
df = read_bigdeal(dm)
if len(df) == 0:
return None
buy_amount = df[df["jyzd"] == 1]["cje"].sum()
sell_amount = df[df["jyzd"] == 2]["cje"].sum()
neutral_amount = df[df["jyzd"] == 0]["cje"].sum()
net_flow = buy_amount - sell_amount
total_amount = buy_amount + sell_amount + neutral_amount
return {
"buy_amount": buy_amount,
"sell_amount": sell_amount,
"net_flow": net_flow,
"buy_ratio": buy_amount / total_amount if total_amount > 0 else 0,
"sell_ratio": sell_amount / total_amount if total_amount > 0 else 0,
"direction": "净买入" if net_flow > 0 else "净卖出"
}
把这些模块整合起来,形成完整的大宗交易分析报告。
def generate_bigdeal_report(dm):
classification = classify_bigdeal(dm)
frequency = analyze_bigdeal_frequency(dm)
performance = analyze_post_bigdeal_performance(dm)
direction = summarize_bigdeal_direction(dm)
report = f"大宗交易分析报告 - {dm}\n"
if classification:
report += f"折溢价信号: {classification['signal']} (评分: {classification['score']})\n"
report += f"平均折溢价: {classification['avg_discount']:.2f}%\n"
report += f"交易笔数: {classification['deal_count']}\n"
if frequency:
report += f"30日内交易频率: {frequency['total_deals']}笔\n"
report += f"频率信号: {frequency['frequency_signal']}\n"
if direction:
report += f"大单方向: {direction['direction']}\n"
report += f"净流入金额: {direction['net_flow']/10000:.1f}万\n"
if performance:
report += f"大宗后5日平均收益: {performance['avg_return_5d']:.2f}%\n"
report += f"大宗后5日胜率: {performance['win_rate']:.1f}%\n"
return report
实际运行下来,这个系统帮我筛选出了几只溢价成交的股票,后续表现确实不错。溢价成交是最强的看多信号——买方愿意以高于市价的价格买入大额筹码,说明他们非常看好。
在使用过程中有几点经验。第一,大宗交易的折价是正常的,因为买方要承担锁定期风险,折价5%以内不用太担心。第二,溢价成交是稀有信号,全市场一年也出现不了几次,一旦出现要重点关注。第三,连续多笔大宗交易是负面信号,说明有人在持续出货。
大宗交易数据是大资金意图的直接体现。用数据来追踪这些信号,比看消息面靠谱多了。
我用的数据来自本地数据引擎,大单成交数据接口完整,做大宗交易分析很方便。感兴趣的朋友可以参考这个思路来构建自己的追踪系统。
接口说明:
-
time/real/trace/bigdeal/{股票代码} - 大单成交数据
本地路径:数据存放目录/time/real/trace/bigdeal/{dm}
主要字段:成交时间(cjsj)、成交价格(cjjg)、成交量(cjl)、交易方向(jyzd)(0中性/1买入/2卖出) -
time/real/{股票代码} - 实时行情
本地路径:数据存放目录/time/real/{dm}
主要字段:成交价格(cjjg)、成交量(cjl) -
time/history/trade/{股票代码}/day - 日线历史K线
本地路径:数据存放目录/time/history/trade/{dm}/day
主要字段:成交时间(cjsj)、成交价格(cjjg)、成交量(cjl)、涨跌幅(zf) -
base/gplist - 股票列表
本地路径:数据存放目录/base/gplist
用于获取全市场股票代码列表
资料参考:ig50

186

被折叠的 条评论
为什么被折叠?



