今天在 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.py8 进程增量补当日数据 + 跑策略 + 飞书推送2~3 分钟
回填模式python main.py --backfill单线程保守拉全市场历史 K 线,自动多轮重跑约 12 分钟

回填模式刻意用单线程 + 自动重试,是为了在 baostock 免费接口偶发不稳定时更稳妥;日常模式则要追求速度,所以用 8 进程并行。这种"一次性稳妥、日常要快"的取舍很务实。

2.3 数据层:为什么用后复权

README 明确解释了复权方式的选择——后复权(hfq)

历史价格不变,适合增量存储,避免除权导致数据错乱。

前复权会把历史价格随每次除权重算,增量场景下一旦发生新的除权,旧数据就需要全部纠正;后复权保持历史价格不变,只在新数据上叠加影响,天然适配"只追加、不回改"的本地 SQLite 存储。数据落地路径为 data/sequoia_v2.db,可直接拷贝迁移到其他机器。

2.4 策略层:基类 + 策略模式

所有策略继承自 BaseStrategymain.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.pyget_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=100target-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.pyBaseStrategy,实现 run() 返回标的列表,然后在 main.pystrategies 列表里追加一行即可,无需改动编排逻辑。

六、总结

Sequoia-X 的价值不在于发明了多新奇的策略,而在于把"量化选股"真正做成了一件可日常运转的工程:清晰的 OOP 分层、向量化的计算、免费且反爬友好的数据层、以及一键 crontab 化的推送闭环。对于想从"囤了一堆策略脚本"走向"每天稳定产出选股信号"的 A 股量化爱好者,它是一个很值得借鉴的参考实现。

如果你打算实盘跟随推送信号,请务必牢记:任何技术面策略都有回撤周期,系统化只是让执行更纪律,不代表策略本身无风险。