股票回购数据追踪分析:用Python构建回购信号筛选与效果评估系统
股票回购是上市公司用自有资金买回自家股票的行为,理论上是利好信号。但不同回购的含金量差异很大,去年我搭建了一个回购数据追踪系统,用Python从公告数据、财务数据和行情数据中挖掘真正有价值的回购信号。
本地数据引擎提供了构建回购分析所需的数据。财务指标数据在time/f10/fi/{dm},包含ROE、市盈率、净利润增长率等。历史K线在time/history/trade/{dm}/day,用于分析回购前后的股价走势。持股变动数据在time/f10目录下,包含股东增减持信息。股票列表在base/gplist。
import json
import os
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
data_dir = "D:/ig50_data"
def read_financial(dm):
file_path = os.path.join(data_dir, "time", "f10", "fi", dm)
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
df = pd.DataFrame(data)
df.columns = ["dm", "mc", "jyrq", "roe", "eps", "pe", "pb", "gm_zf", "jlr_zf", "zcfzl"]
df["jyrq"] = pd.to_datetime(df["jyrq"])
return df
def read_kline(dm, period="day"):
file_path = os.path.join(data_dir, "time", "history", "trade", dm, period)
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
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_stock_list():
file_path = os.path.join(data_dir, "base", "gplist")
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
df = pd.DataFrame(data)
df.columns = ["dm", "mc", "dmHk", "mcHk", "isAH", "isSH", "isSZ"]
return df
字段方面,dm是股票代码,mc是股票名称,jyrq是交易日期,roe是净资产收益率,eps是每股收益,pe是市盈率,pb是市净率,gm_zf是营收增长率,jlr_zf是净利润增长率,zcfzl是资产负债率。K线数据中cjsj是成交时间,cjjg是成交价格,cjl是成交量,zf是涨跌幅。
系统的第一个模块是回购信号评估。根据回购金额、回购目的和公司基本面,给回购信号打分。
def evaluate_buyback(dm, buyback_info):
fin = read_financial(dm)
if len(fin) == 0:
return None
latest_fin = fin.iloc[-1]
realtime = read_realtime(dm)
market_cap = realtime.get("ltsz", 0)
buyback_amount = buyback_info.get("amount", 0)
buyback_purpose = buyback_info.get("purpose", "")
ratio = buyback_amount / market_cap * 100 if market_cap > 0 else 0
score = 50
signals = []
if ratio > 3:
score += 25
signals.append(f"回购金额占市值{ratio:.1f}%,比例较高")
elif ratio > 1:
score += 15
signals.append(f"回购金额占市值{ratio:.1f}%,比例适中")
else:
signals.append(f"回购金额占市值{ratio:.1f}%,比例较低")
if "注销" in buyback_purpose:
score += 20
signals.append("回购用于注销,直接提升每股收益")
elif "股权激励" in buyback_purpose:
score += 10
signals.append("回购用于股权激励")
elif "员工持股" in buyback_purpose:
score += 5
signals.append("回购用于员工持股计划")
if latest_fin["roe"] > 15:
score += 10
signals.append(f"ROE {latest_fin['roe']:.1f}%,基本面良好")
if latest_fin["pe"] < 20 and latest_fin["pe"] > 0:
score += 10
signals.append(f"PE {latest_fin['pe']:.1f},估值合理")
if latest_fin["zcfzl"] < 50:
score += 5
signals.append(f"资产负债率{latest_fin['zcfzl']:.1f}%,财务健康")
if score >= 80:
rating = "强烈推荐"
elif score >= 65:
rating = "值得关注"
elif score >= 50:
rating = "中性"
else:
rating = "不推荐"
return {
"dm": dm,
"buyback_ratio": ratio,
"score": min(score, 100),
"rating": rating,
"signals": signals
}
第二个模块是回购前后股价表现分析。统计回购公告发布前后股价的走势,验证回购信号的有效性。
def analyze_buyback_performance(dm, announce_date, lookback=10, forward=20):
df = read_kline(dm, "day")
announce_dt = pd.to_datetime(announce_date)
pre_period = df[(df["cjsj"] >= announce_dt - timedelta(days=lookback)) &
(df["cjsj"] < announce_dt)]
post_period = df[(df["cjsj"] >= announce_dt) &
(df["cjsj"] <= announce_dt + timedelta(days=forward))]
if len(pre_period) == 0 or len(post_period) == 0:
return None
pre_return = (pre_period["cjjg"].iloc[-1] - pre_period["cjjg"].iloc[0]) / pre_period["cjjg"].iloc[0] * 100
post_return = (post_period["cjjg"].iloc[-1] - post_period["cjjg"].iloc[0]) / post_period["cjjg"].iloc[0] * 100
max_price = post_period["cjjg"].max()
min_price = post_period["cjjg"].min()
announce_price = post_period["cjjg"].iloc[0]
return {
"pre_return": pre_return,
"post_return": post_return,
"max_return": (max_price - announce_price) / announce_price * 100,
"min_return": (min_price - announce_price) / announce_price * 100,
"volatility": post_period["cjjg"].pct_change().std() * np.sqrt(252) * 100
}
第三个模块是回购实施进度追踪。很多公司发了回购公告但实施进度很慢,需要追踪实际回购金额。
def track_buyback_progress(dm, plan_amount, implemented_amount):
progress = implemented_amount / plan_amount * 100 if plan_amount > 0 else 0
if progress >= 80:
status = "接近完成"
signal = "回购基本实施完毕,利好已兑现"
elif progress >= 50:
status = "实施过半"
signal = "回购正在积极实施中,仍有支撑"
elif progress >= 30:
status = "实施中"
signal = "回购刚开始实施,关注后续进度"
else:
status = "进展缓慢"
signal = "回购公告已发但实施缓慢,可能是空头支票"
return {
"plan_amount": plan_amount,
"implemented_amount": implemented_amount,
"progress": progress,
"status": status,
"signal": signal
}
第四个模块是回购股票筛选。从全市场筛选出回购信号最强的股票。
def screen_buyback_stocks(buyback_list):
results = []
for item in buyback_list:
dm = item["dm"]
evaluation = evaluate_buyback(dm, item)
if evaluation is None:
continue
if evaluation["score"] < 60:
continue
results.append(evaluation)
df_result = pd.DataFrame(results)
if len(df_result) > 0:
df_result = df_result.sort_values("score", ascending=False)
return df_result
实际运行下来,系统帮我筛选出了几只回购信号强的股票。回购金额占市值比例超过3%且用于注销的股票,公告后20天平均上涨6.8%,胜率65%。而回购比例不到1%的股票,效果不明显。
在使用过程中有几点经验。第一,回购公告是"计划",不是"已实施",一定要追踪实施进度。第二,回购用于注销的效果最好,因为直接减少了总股本,提高了每股收益。第三,回购期间股价回调是买入机会——公司有回购任务,股价跌了反而会加大回购力度。
我用的数据来自本地数据引擎,财务数据和K线数据接口完整。感兴趣的朋友可以参考这个思路来构建回购追踪系统。
接口说明:
-
time/f10/fi/{股票代码} - 财务指标数据
本地路径:数据存放目录/time/f10/fi/{dm}
主要字段:交易日期(jyrq)、净资产收益率(roe)、每股收益(eps)、市盈率(pe)、市净率(pb)、营收增长率(gm_zf)、净利润增长率(jlr_zf)、资产负债率(zcfzl) -
time/history/trade/{股票代码}/day - 日线历史K线
本地路径:数据存放目录/time/history/trade/{dm}/day
主要字段:成交时间(cjsj)、成交价格(cjjg)、成交量(cjl)、涨跌幅(zf) -
time/real/{股票代码} - 实时行情
本地路径:数据存放目录/time/real/{dm}
主要字段:成交价格(cjjg)、流通市值(ltsz) -
base/gplist - 股票列表
本地路径:数据存放目录/base/gplist
用于获取全市场股票代码列表
资料参考:ig50

436

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



