【python量化】基于 Tushare 的简单选股策略验证:一次失败但有价值的轻量级回测实践
·
基于 Tushare 的简单选股策略验证:一次轻量级回测实践
一、背景
在完成基础筛选和加入均线判断之后,一个更实际的问题是:
👉 筛选出来的股票,到底有没有“效果”?
也就是说,仅仅看到“涨幅 + 均线向上”还不够,
还需要进一步验证:这种筛选方式,在历史数据中是否具备一定参考价值。
因此,这一篇主要做一件事情:
对之前的选股规则做一个简单的收益验证。
不使用复杂回测框架,只做一个轻量级实现。
二、策略说明
沿用上一版的筛选逻辑:
- 剔除 ST 股票
- 收盘价 < 20 元
- 当日涨幅 > 3%
- MA5 > MA10
在此基础上,加一个验证方式:
👉 假设在筛选日买入,持有 N 天后卖出,计算收益
本次设定:
- 持有周期:5 个交易日
三、实现思路
整体流程如下:
- 获取一段时间的历史数据
- 计算均线
- 在每个交易日进行筛选
- 对筛选结果计算未来收益
- 汇总结果
四、数据准备
import tushare as ts
import pandas as pd
ts.set_token('你的token')
pro = ts.pro_api()
获取较长时间区间的数据(用于回测):
df = pro.daily(
start_date='20240101',
end_date='20240329'
)
五、计算均线
g = df.groupby("ts_code", group_keys=False)
df["ma5"] = g["close"].transform(lambda x: x.rolling(5).mean())
df["ma10"] = g["close"].transform(lambda x: x.rolling(10).mean())
df["ma20"] = g["close"].transform(lambda x: x.rolling(20).mean())
df["vol_ma5"] = g["vol"].transform(lambda x: x.rolling(5).mean())g(20).mean())
六、构造未来收益
这里是关键步骤。
计算未来 5 天收益:
# 未来收益:持有 HOLD_DAYS 个交易日
df["future_close"] = g["close"].shift(-HOLD_DAYS)
df["future_return"] = (df["future_close"] - df["close"]) / df["close"]
# 下一交易日开盘收益(可选,看起来更接近“次日再买”)
df["next_open"] = g["open"].shift(-1)
df["future_close_from_next_open"] = g["close"].shift(-(HOLD_DAYS + 1))
df["future_return_next_open"] = (
(df["future_close_from_next_open"] - df["next_open"]) / df["next_open"]
)
解释一下:
shift(-n)表示取未来第n天的价格- 用来模拟“持有n天后卖出”
七、逐日筛选并统计结果
results = []
for date in df['trade_date'].unique():
daily = df[df['trade_date'] == date]
# 筛选条件
selected = daily[
(daily['pct_chg'] > 3) &
(daily['close'] < 20) &
(daily['ma5'] > daily['ma10'])
]
if len(selected) > 0:
avg_return = selected['return'].mean()
results.append(avg_return)
八、结果分析
summary = {
"信号总数": int(len(signals)),
"有信号交易日数": int(len(daily_result)),
"单笔平均收益": float(signals["strategy_return"].mean()),
"单笔收益中位数": float(signals["strategy_return"].median()),
"单笔胜率": float((signals["strategy_return"] > 0).mean()),
"按日等权平均收益": float(daily_result["avg_return"].mean()),
"按日等权胜率": float((daily_result["avg_return"] > 0).mean()),
"最终净值": float(daily_result["equity"].iloc[-1]),
"最大单日回撤": float((daily_result["equity"] / daily_result["equity"].cummax() - 1).min())
}
print("\n===== 回测结果汇总 =====")
for k, v in summary.items():
if isinstance(v, float):
print(f"{k}: {v:.4f}")
else:
print(f"{k}: {v}")

九、结果可视化
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
plt.plot(daily_result["trade_date"], daily_result["equity"], linewidth=1.5)
plt.xticks(rotation=45)
plt.title("Simple Tushare Strategy Equity Curve")
plt.xlabel("Trade Date")
plt.ylabel("Equity")
plt.tight_layout()
plt.savefig(OUTPUT_DIR / "equity_curve.png", dpi=150)
plt.show()

十、结果解读
在当前样本区间内,这组条件未取得理想结果。
从回测结果看,策略累计净值持续回落,胜率和平均收益也偏弱,说明仅使用“涨幅 + 均线 + 放量”作为筛选条件,尚不足以形成稳定的短线策略。
十一、方法特点
这个回测方法比较简单,有几个特点:
- 不依赖复杂框架
- 计算逻辑清晰
- 适合快速验证想法
但也存在明显限制:
- 未考虑交易成本
- 未考虑滑点
- 未做仓位管理
- 未考虑风险控制
因此更适合作为“初步验证”。
十二、可以继续优化的方向
在这个基础上,可以进一步做:
- 加入止盈止损
- 引入成交量条件
- 多策略组合
- 使用专业回测框架(如 backtrader)
十三、总结
这一步的核心其实不是策略本身,而是完成了一件更重要的事情:
👉 把“筛选结果”转化为“可以量化验证的结果”
相比只看某一天的筛选名单,这种方式更接近实际应用。
虽然当前实现还比较简单,但已经可以作为后续优化策略的基础。
更多推荐



所有评论(0)