今天在 GitHub Trending 上看到一个有意思的项目:Sequoia-X,一个面向 A 股市场的量化选股系统。它最大的亮点是用现代 Python 工程化标准从零重构,把"收盘后自动选股 + 推送到飞书群"这件手工活,做成了一套可日复一日稳定跑起来的系统。
一、项目概述
Sequoia-X V2 是一套日终选股流水线:每天收盘后,自动补全当日行情数据,跑一批预置的技术面策略,把符合条件的标的通过飞书 Webhook 推送到对应群组。它要解决的核心痛点很朴素——量化爱好者最难的从来不是写出某个策略,而是把"取数 → 计算 → 推送"整条链路工程化、稳定化、可日常化。
核心特性可以归纳为四点:
- OOP 分层架构:数据层、策略层、通知层彻底解耦,新增策略只需继承一个基类。
- 向量化计算:基于 pandas 做批量运算,避免逐行 Python 循环带来的性能瓶颈。
- 增量数据更新:日常模式 8 进程并行拉取,2~3 分钟完成全市场快照,而非每次重算全历史。
- 零反爬数据层:用免费、无需注册、无限流的
baostock拉取后复权日 K,绕开了东方财富等接口的反爬限制。
项目地址:https://github.com/sngyai/Sequoia-X (MIT 协议)
二、技术原理
2.1 整体架构
从 pyproject.toml 的依赖声明和 main.py 的导入结构,可以清晰看到系统的分层:
sequoia_x/
├── core/ # 配置与日志(Pydantic-settings + rich)
│ ├── config.py
│ └── logger.py
├── data/
│ └── engine.py # 数据引擎:baostock 回填 + 增量同步 + SQLite
├── strategy/ # 策略层:抽象基类 + 7 个具体策略
│ ├── base.py
│ ├── turtle_trade.py
│ ├── ma_volume.py
│ ├── rps_breakout.py
│ └── ...
└── notify/
└── feishu.py # 飞书 Webhook 推送
这种设计的好处是:main.py 只负责"编排",真正的能力都下沉到各层。入口函数非常干净:
def main() -> None:
parser = argparse.ArgumentParser(description="Sequoia-X V2 选股系统")
parser.add_argument(
"--backfill",
action="store_true",
help="回填模式:通过 baostock 拉取全市场历史 K 线(约12分钟)",
)
args = parser.parse_args()
# ...初始化配置、日志、数据引擎
if args.backfill:
all_symbols = engine.get_all_symbols()
engine.backfill(all_symbols)
return
# 日常模式:拉快照 → 跑策略 → 推送
2.2 两种运行模式
系统通过 argparse 区分两种模式,对应不同的数据节奏:
| 模式 | 命令 | 行为 | 耗时 |
|---|---|---|---|
| 日常模式 | python main.py | 8 进程增量补当日数据 + 跑策略 + 飞书推送 | 2~3 分钟 |
| 回填模式 | python main.py --backfill | 单线程保守拉全市场历史 K 线,自动多轮重跑 | 约 12 分钟 |
回填模式刻意用单线程 + 自动重试,是为了在 baostock 免费接口偶发不稳定时更稳妥;日常模式则要追求速度,所以用 8 进程并行。这种"一次性稳妥、日常要快"的取舍很务实。
2.3 数据层:为什么用后复权
README 明确解释了复权方式的选择——后复权(hfq):
历史价格不变,适合增量存储,避免除权导致数据错乱。
前复权会把历史价格随每次除权重算,增量场景下一旦发生新的除权,旧数据就需要全部纠正;后复权保持历史价格不变,只在新数据上叠加影响,天然适配"只追加、不回改"的本地 SQLite 存储。数据落地路径为 data/sequoia_v2.db,可直接拷贝迁移到其他机器。
2.4 策略层:基类 + 策略模式
所有策略继承自 BaseStrategy,main.py 用统一的列表遍历执行,新增策略只改一个列表:
strategies: list[BaseStrategy] = [
MaVolumeStrategy(engine=engine, settings=settings),
TurtleTradeStrategy(engine=engine, settings=settings),
HighTightFlagStrategy(engine=engine, settings=settings),
LimitUpShakeoutStrategy(engine=engine, settings=settings),
UptrendLimitDownStrategy(engine=engine, settings=settings),
RpsBreakoutStrategy(engine=engine, settings=settings),
PrivatePlacementStrategy(engine=engine, settings=settings),
]
for strategy in strategies:
strategy_name = type(strategy).__name__
selected = strategy.run() # 统一接口
if selected:
notifier.send(
symbols=selected,
strategy_name=strategy_name,
webhook_key=strategy.webhook_key, # 每个策略推到自己的飞书群
)
内置的 7 类策略覆盖了主流技术面形态:
- TurtleTrade:海龟突破,20 日新高 + 成交额过亿 + 阳线防诱多。
- MaVolume:均线 + 放量突破。
- HighTightFlag:高而窄的旗形整理突破(经典趋势延续形态)。
- LimitUpShakeout:涨停洗盘回踩确认。
- UptrendLimitDown:上升趋势中的跌停反包。
- RpsBreakout:欧奈尔 RPS 相对强度突破。
- PrivatePlacement:定增相关策略。
值得注意的是每个策略绑定独立的 webhook_key,意味着不同策略的选股结果会推送到不同的飞书群,互不干扰——这对实盘纪律很有意义。
三、安装与快速开始
3.1 环境要求
- Python >= 3.10
- 推荐用
uv管理依赖(也支持pip)
3.2 安装步骤
# 推荐:uv 一键同步依赖
uv sync
# 或传统方式
pip install .
3.3 配置飞书 Webhook
复制环境变量模板并填写飞书机器人的 Webhook URL:
cp .env.example .env
# 编辑 .env,填入 FEISHU_WEBHOOK 等相关配置
配置通过 pydantic-settings 管理(core/config.py 的 get_settings()),配合 python-dotenv 自动加载 .env,比手写 os.getenv 更类型安全。
3.4 首次回填 + 日常运行
# 首次/补数据:回填全市场历史后复权日 K(约 12 分钟)
python main.py --backfill
# 之后每个交易日收盘后日常运行
python main.py
四、使用方法与实战
4.1 用 crontab 自动化
README 给出的推荐姿势是交给 crontab,在交易日 19:15(收盘后约 45 分钟,留出数据落地时间)自动执行:
15 19 * * 1-5 cd /root/Sequoia-X && .venv/bin/python main.py >> log.txt 2>&1
1-5 限定为周一到周五,天然跳过周末;日志追加到 log.txt 便于排查某天推送缺失的原因。
4.2 工程化细节
- 结构化日志:用
rich做彩色结构化日志(core/logger.py),logger.info/f exception让异常链清晰可读。 - 故障兜底:
main()外层包了try/except,未捕获异常会先尝试用 logger 记录完整堆栈再sys.exit(1),避免静默失败。 - 属性测试:
tests/目录使用hypothesis做基于属性的测试,比传统样例测试更能打边界情况。 - 代码质量:
ruff配置了E/F/I/UP规则集,line-length=100,target-version=py311,符合现代 Python 规范。
五、常见问题与解决方案
Q1:回填(backfill)经常中断 / 拉不全?
回填模式特意用单线程 + engine.backfill 内部"自动多轮重跑"来对抗 baostock 免费接口的偶发不稳定。若仍中断,可重跑 --backfill,增量机制会续拉未完成的标的。
Q2:日常运行推送报错 / 收不到飞书消息?
检查 .env 中的飞书 Webhook URL 是否正确,以及对应群机器人的权限。注意每个策略用各自 webhook_key,某个策略推送失败不影响其他策略。
Q3:数据看起来"对不上",价格忽高忽低? 多半是复权方式理解偏差。系统统一用后复权存储,历史价格不变;若你用前复权口径对比其他软件,会出现差异,这是预期行为而非 bug。
Q4:拉取数据时连接超时?
main.py 顶部已设置 socket.setdefaulttimeout(10.0) 做全局超时保护;如网络较差可适当调大,或确认 baostock 服务可用性。
Q5:想加自己的策略?
继承 sequoia_x/strategy/base.py 的 BaseStrategy,实现 run() 返回标的列表,然后在 main.py 的 strategies 列表里追加一行即可,无需改动编排逻辑。
六、总结
Sequoia-X 的价值不在于发明了多新奇的策略,而在于把"量化选股"真正做成了一件可日常运转的工程:清晰的 OOP 分层、向量化的计算、免费且反爬友好的数据层、以及一键 crontab 化的推送闭环。对于想从"囤了一堆策略脚本"走向"每天稳定产出选股信号"的 A 股量化爱好者,它是一个很值得借鉴的参考实现。
如果你打算实盘跟随推送信号,请务必牢记:任何技术面策略都有回撤周期,系统化只是让执行更纪律,不代表策略本身无风险。