Sequoia-X 项目研究站 · 日常运行

Sequoia-X 日常运行:补增量、跑策略、推飞书的一次闭环

装好之后的每个交易日,你只需要执行一次 python main.py。它会先读本地库里已有的股票清单、把当日缺失的日 K 按股票切成最多八份并行补回来,然后依次跑七个形态策略,只有命中的策略才会把结果推到飞书。整个过程由 rich 输出带时间戳的日志,最后用 crontab 固定在收盘后执行。

日常模式:约 2~3 分钟(README 自述)并发:最多 8 个进程分片拉取依据 main.py 与 data/engine.py(2026-09 核验)
读取本地清单从 SQLite 取 symbol 与最新日期
8 进程增量tasks[i::n] 分片并行拉取
依次跑策略7 个策略顺序执行
命中才推送无结果只记日志
日常运行闭环示意(依据 main.py 与 data/engine.py 整理,非官方流程图)。
依据来源官方 README · pyproject · .env.example
本页引用main.py · sequoia_x/data/engine.py
核验方式源码静态核验 + 本站实测(2026-10-10 在 Windows / Python 3.11.9 真机跑通安装、回填、日常运行与推送)
核验基准commit 444c0db(2026-05-09)· Python ≥3.10 · 2026-10-12 质检复核(含 2026-10-10 本站实测)
Daily loop

Sequoia-X 日常模式有哪五步?

步骤与顺序来自 main.py 的日常分支,不是推测。

  1. 读本地股票清单

    从 SQLite 里 SELECT symbol, MAX(date) FROM stock_daily GROUP BY symbol 取出每只股票的最新日期。若库里一只股票都没有,日志会提示「本地无股票数据,请先执行 --backfill」并直接返回——这是首次运行的正常提示。

  2. 算出需要补哪些股票

    只对「最新日期早于今天」的股票生成任务;已经是最新的会被跳过。所有股票都是最新时,日志输出「所有股票已是最新,无需更新」,不做任何网络请求。

  3. 八进程并行拉当日增量

    任务按 tasks[i::n] 切成 min(8, 任务数) 份,每个子进程自己 bs.login() 独立拉取,避免单连接串行等待。子进程返回的行在父进程汇总成 DataFrame。

  4. 清洗后写回 SQLite

    数值列转数字、丢掉收盘价为空的记录、过滤 volume <= 0 的停牌行;写入前先 DELETE FROM stock_daily WHERE date = ?,再按批量 append,保证同一天重复执行不会产生重复行。

  5. 跑七个策略并按需推送

    策略在 main.py 的列表里顺序执行,每个策略读同一份本地数据、返回命中的股票代码;命中为空只记日志,命中的才调用飞书推送器并带上该策略的 webhook_key。

一次执行只做一天:日常模式的设计假设是「每天收盘后跑一次」。如果要补多天历史,用的是回填模式(--backfill),它在安装与回填页里说明。两者不要混着用:日常模式为了补当日缺口会删掉当日记录再写,回填模式则是逐只增量追加。
Mechanism

Sequoia-X 的八进程增量做了什么

把并发、去重与容错拆开看,出问题时才知道该查哪一环。

环节源码行为适用场景注意点
进程数n_workers = min(8, len(tasks))全市场日常更新待补股票少于 8 只时进程数自动减少,不会空跑
任务分片chunks = [tasks[i::n_workers] for i in range(n_workers)]把清单均匀摊到各进程按步长切分而非按块,各进程负载更均衡
连接管理每个子进程独立 bs.login() / bs.logout()多进程并发取数不共享连接,避免单连接超时影响全部任务
增量起点从「该股票最新日期 + 1 天」拉到今天按股票精确补缺口库中日期格式需为 YYYY-MM-DD,否则日期解析会失败
清洗规则丢弃 close 为空、过滤 volume <= 0剔除停牌与脏行停牌日不会进入策略计算,形态窗口按实际交易日滚动
写入去重先按日期 DELETE 再 append同一天重复运行手工重跑当天的日常模式是安全的;但不要用它补历史
空结果无新行时输出「无新数据(可能非交易日)」并返回 0周末与法定节假日这是预期行为,不要据此判定脚本坏了
Schedule

怎么用 crontab 让 Sequoia-X 收盘后自动运行?

官方 README 给出的定时方式是 crontab,示例行如下。

crontab15 19 * * 1-5 cd /root/Sequoia-X && .venv/bin/python main.py >> log.txt 2>&1
片段含义适用场景注意点
15 19 * * 1-5周一到周五 19:15 执行A 股收盘(15:00)后数小时crontab 不识别节假日,节假日会照跑并输出「无新数据」
cd /root/Sequoia-X切到项目目录再执行数据库相对路径为 data/sequoia_v2.db不切目录会按 cron 的家目录找 data/,等于换了一个空库
.venv/bin/python用虚拟环境里的解释器依赖装在 venv 里直接写 python 会用到系统解释器,报模块找不到
>> log.txt 2>&1标准输出与错误都追加到日志文件cron 环境没有终端不加这一段的输出会被丢弃,出问题无从查起
环境变量cron 默认不加载你的 shell 配置项目用 .env + load_dotenv() 读配置把飞书 Webhook 写进项目目录的 .env,不要在 cron 行里硬编码密钥
改成多时段把 15 19 换成别的时间数据源当日数据更新较晚时当日数据未就绪时拉到空结果属正常,可顺延时间再跑一次
非 Linux 环境:官方只提供 crontab 示例。Windows 可用「任务计划程序」、macOS 可用 launchd 或 cron,做法等价:切到项目目录、用虚拟环境解释器、把输出重定向到日志文件。本项目没有内置调度器,也没有守护进程。
Duration

Sequoia-X 运行耗时与影响因素

README 的自述数字只作参考,实际耗时随环境变化。

运行类型官方自述耗时主要影响因素怎么判断正常
日常模式约 2~3 分钟待补股票数量、网络质量、机器 CPU 核数、策略遍历全库的耗时日志里能看到「需要更新 N 只股票」与每条策略的选股数量
首次回填约 12 分钟单线程逐只拉取、起始日期(默认 2024-01-01)到今天的长度、重试与重连次数每 500 只打印一行「已处理 x/N,成功/跳过/失败」
跳过的情形数秒全部股票已是最新,或当天不是交易日日志出现「所有股票已是最新」或「无新数据(可能非交易日)」
策略阶段未单独给出逐只读库 + 向量化计算的规模;定增策略另需请求 akshare每个策略结束都有一行「XXXStrategy 选出 N 只股票」
推送阶段逐策略最多 10 秒超时Webhook 响应速度;推送前还要查股票名称成功会记「飞书推送成功 [key],共 N 只股票」
数据规模约 5200 只 A 股(README 口径)股票清单来自 bs.query_stock_basic() 的上市股票过滤回填开始时日志会打印「获取股票列表完成,共 N 只」
Logs

日志怎么读

日志用 rich 输出,格式固定为「模块名 - 消息」,带方括号时间戳。

典型日常运行日志[2026-09-15 19:15:02] sequoia_x.core.logger - Sequoia-X V2 启动 [2026-09-15 19:15:02] sequoia_x.data.engine - 数据库初始化完成:data/sequoia_v2.db [2026-09-15 19:15:02] sequoia_x.data.engine - 需要更新 5183 只股票,启动多进程并行拉取... [2026-09-15 19:16:41] sequoia_x.data.engine - sync_today_bulk: 写入 5183 条数据 [2026-09-15 19:16:44] sequoia_x.strategy.ma_volume - MaVolumeStrategy 选出 12 只股票 [2026-09-15 19:16:45] sequoia_x.notify.feishu - 飞书推送成功 [ma_volume],共 12 只股票
日志特征含义适用场景注意点
时间戳格式 [%Y-%m-%d %H:%M:%S]由 RichHandler 统一渲染排查某天是否真的跑过重定向到文件后不带颜色,属正常
日志级别是 DEBUGlogger 默认设为 DEBUG需要更细的库内输出时日志会比较长,定时任务建议只保留最近若干天
WARNING 行带股票代码单只股票计算失败被跳过,不影响其他股票个别标的 K 线不足或数据异常策略内异常被捕获后写 warning,主流程继续
「无选股结果,跳过推送」该策略当天没有命中标的阈值较严或当日行情不匹配不是错误,也不会发空卡片到飞书
「主流程发生未捕获异常」+ traceback顶层异常处理器打印后以退出码 1 结束配置缺失、数据库不可写等cron 不会通知你,建议配合日志检查或另设告警
同名 logger 只挂一个 handler重复调用取 logger 不会重复打印二次开发时自定义模块取日志日志不重复说明幂等逻辑生效,属正常现象
When to run

Sequoia-X 该什么时候跑:四个时点的实际后果

日常模式读的是「库内最新的那根 K 线」,而它写入的结束日期是 date.today()。所以「几点跑」会直接改变结果,这不是配置细节。

时点会发生什么(源码行为)对你的影响建议
开盘前(9:00 前)当日尚无成交,增量拉不到新行,脚本继续跑策略Sequoia-X 基于上一交易日数据再算一遍,可能重复推送昨天的名单不要放在开盘前;确实要跑就只看日志、忽略推送
盘中(交易时段)结束日期是当天,baostock 返回的当日日 K 可能是尚未收盘的快照若当天不再重跑,库里会留下一根不完整的当日 K 线,并被次日形态判定使用不要在盘中跑;如已跑,收盘后再跑一次——源码会先 DELETE 当日记录再写入,可以覆盖
收盘后(15:30 之后)当日日 K 已完整,增量写入、策略按完整数据判定,命中才推送这是语义上正确的时点crontab 建议 30 15 * * 1-5(工作日 15:30)
周末与节假日无新数据,日志输出「所有股票已是最新」或「无新数据」——但脚本仍会继续执行策略并推送手动再跑一次会重复收到与上一个交易日完全相同的卡片把定时限定在工作日;手动重跑时留意重复推送
补跑多天未运行增量只会补到「最新一根」之后的日期,不会逐日重放历史缺的中间交易日不会自动补齐缺得多就走回填模式(已入库的会被跳过)
为什么会重复推送:源码里没有「当日已推送就跳过」的判断——增量写入为 0 条时只记一行日志,随后策略照常执行、命中照常 POST。这是读取 Sequoia-X 的 main.py 与 data/engine.py 能确定的结论(已验证源码,未在本机运行验证),具体行为以官方源码为准。
Measured: off-day

本站实测:非交易日跑一次会发生什么?

2026-10-10 是周六。本站用真实的 789 只库、真实的 baostock、Webhook 指向本机 mock 服务(不打扰任何群),完整跑了一次 python main.py。整个过程 49.6 秒,日志如下。

环节日志原文 / 读数说明
数据层需要更新 265 只股票,启动多进程并行拉取... → sync_today_bulk: 写入 0 条数据所有标的都在队列里(因为它们的最后日期 2026-10-09 早于今天),但窗口 [今天, 今天] 取不到任何数据
策略层MaVolumeStrategy 选出 5 只、TurtleTradeStrategy 选出 13 只、RpsBreakoutStrategy 选出 7 只(本次运行库内 265 只);高窄旗形、涨停洗盘、上升跌停、定增监控均 0 只。另一次在 789 只样本上的独立运行给出 16 / 33 / 23 只——命中数随样本规模变化,本身不说明策略优劣策略没有检查「今天有没有新数据」,直接对着库里最后一根 K 线(2026-10-09)计算
推送层收到 3 条真实请求:/hook/ma_volume、/hook/turtle、/hook/rps;卡片内 **日期:** 2026-10-10推送照发,卡片上的日期是今天,数据其实是上一个交易日
退出码exit=0,日志最后一行 Sequoia-X V2 运行完成从程序的角度这是一次「成功运行」,没有任何告警

后果一:名单会重复推送

策略读的是库里最后一根 K 线。周六、周日、以及任何一个「数据没更新的日子」,跑一次就会把同一个交易日的名单再推一遍。想在群里看「今天新增了什么」的人,会被连续几天的相同名单误导。

后果二:日期标签与数据脱节

卡片里的日期来自 date.today(),而名字来自上一交易日。周五收盘生成的名单,在周六的推送里会写「日期:周六」。事后翻记录时,很容易把这条当成周六的信号。

做法怎么落地代价 / 局限
只让交易日的 19:00 后触发cron 写 15 19 * * 1-5(README 的写法);Windows 任务计划只勾周一至周五避开周末,但避不开节假日(周三国庆仍会触发)
跑之前先判交易日在 main.py 之前加一层:库内 MAX(date) 等于今天才继续;或用交易日历文件判断需要自己加包装脚本;改动正式流程,建议先小范围验证
让策略只在「当天有新数据」时执行把 sync_today_bulk() 的返回值 0 当作「今天没有新数据,跳过策略与推送」这是最小改动:仅当返回值 > 0 才继续。但注意「非交易日返回 0」与「取数失败也返回 0」此时无法区分
推送内容带数据日期卡片里把「数据日期」与「运行日期」分开写(现在只有一个日期字段)不改行为,只降低误读风险;属于你自己改 _build_card 的范畴
这条实测回答的问题:「非交易日如何避免重复推送旧数据」——本项目没有内置这个保护,它只保证「不写入」,不保证「不推送」。默认行为是数据不动、策略照算、消息照发。要不要拦,得你自己在编排层或推送前加判断。
Windows

Windows 任务计划怎么建、日志怎么轮转?

项目 README 只给了 Linux crontab。如果你跟本站一样在 Windows 上跑,下面这套是可以直接照抄的方案(流程与命令为本站整理,未在本机注册任务,因此标注为教程扩展而非实测)。

  1. 先写一个包装脚本,解决三件事

    任务计划里的命令不会帮你切目录、不会展开安全的日期文件名、也不会追加日志。先用 run_daily.bat 包一层:

    @echo off
    cd /d D:\Sequoia-X
    for /f %%i in ('powershell -NoProfile -Command "Get-Date -Format yyyy-MM-dd"') do set TODAY=%%i
    if not exist logs mkdir logs
    .venv\Scripts\python.exe main.py >> logs\run_%TODAY%.log 2>&1
    echo [%DATE% %TIME%] exit=%errorlevel% >> logs\run_%TODAY%.log

    要点:cd /d 是必须的(.env 与 data/sequoia_v2.db 都按当前目录解析);%DATE% 直接当文件名会带斜杠,所以用 PowerShell 取 yyyy-MM-dd;日志按天一个文件,方便事后对着日期查。

  2. 注册任务:每周一到周五 18:10

    # 管理员 PowerShell
    $action  = New-ScheduledTaskAction -Execute "D:\Sequoia-X\run_daily.bat" -WorkingDirectory "D:\Sequoia-X"
    $trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Monday,Tuesday,Wednesday,Thursday,Friday -At 18:10
    $settings = New-ScheduledTaskSettingsSet -MultipleInstances IgnoreNew -StartWhenAvailable
    Register-ScheduledTask -TaskName "Sequoia-X-Daily" -Action $action -Trigger $trigger `
      -Settings $settings -Description "Sequoia-X 收盘后增量+选股+飞书推送"

    -MultipleInstances IgnoreNew 是防重入的关键:上一次还没跑完时不再启动新实例。这一条直接对应数据层的删除范围风险——同一天第二次运行会进入「只补少数标的」的分支。

    命令行等价写法(不支持 IgnoreNew,需要靠 XML 或 PowerShell):

    schtasks /Create /TN "Sequoia-X-Daily" /TR "D:\Sequoia-X\run_daily.bat" /SC WEEKLY /D MON,TUE,WED,THU,FRI /ST 18:10 /RL HIGHEST /F
  3. 几点跑:三个时点各自的代价

    时点会发生什么建议
    15:05(收盘即跑)日 K 通常还没出齐,可能取到 0 行,然后按上一交易日推名单不要用
    17:30~18:30当日日 K 基本可得,本项目 README 给的是 19:15可用;建议先手工跑一天确认取到当天数据
    次日 08:00数据一定齐,但当日盘中你才看到昨天的信号只适合「不抢时点」的使用方式
    开盘前 09:00同上,且与早盘操作时间挤在一起观察名单用
  4. 日志轮转:保留 30 天

    forfiles /p D:\Sequoia-X\logs /m run_*.log /d -30 /c "cmd /c del @path"

    把这一行放进一个每周跑一次的任务即可。按天分文件后,删旧日志是安全的;如果你把所有输出追加到同一个 log.txt(README 的 crontab 写法),它会无限增长,而且要定位某一天得靠翻时间戳。

  5. 「数据更新了但策略没跑」怎么分层定位

    层先看什么判断
    数据层SELECT MAX(date) FROM stock_daily; 是否等于今天的交易日不等于 → 取数问题(数据源限流、网络、窗口为空),策略即使跑了也是旧数据
    调度层日志文件是否存在、exit= 是多少、任务计划「上次运行结果」是否是 0x0日志都没生成 → 任务没触发或工作目录不对;有日志但是空的 → 重定向写错位置
    策略层日志里是否有 7 行 执行策略:xxx只跑到「快照同步完成」就结束 → 中途抛异常(退出码 1),往上翻 Traceback
    推送层日志里 飞书推送成功 [key] 还是 飞书推送失败策略选出了票但推送失败 → Webhook/机器人问题,与数据无关;策略 0 只时本来就不会推送
一个容易忽略的坑:任务计划程序没有节假日概念。周一至周五的设置照样会在国庆、春节的工作日休市日触发,那时段的行为就是本页第一条实测:数据不动、名单照推。要彻底解决,需要在包装脚本里加一层交易日判断。
FAQ

日常运行常见问题

每天都必须手动跑一次吗?

不必。官方做法是用 crontab 在工作日收盘后自动执行,示例为 19:15。手动执行等价于把同样一条命令敲一遍,适合调试或补跑当天。具体时间与解释器路径以你的环境和官方 README 为准。

非交易日会报错吗?

不会。没有新数据时日志会输出「无新数据(可能非交易日)」并正常结束,返回写入 0 条。周末与节假日出现这条日志属于预期行为,不要据此判定脚本损坏。

同一天重复运行会写重复数据吗?

日常模式在写入前会按日期先删除当天记录再批量追加,所以手工重跑当天不会产生重复行。但注意表上还有 UNIQUE(symbol, date) 约束,回填路径遇到冲突是把 IntegrityError 静默跳过,两条路径的容错方式不同。

日常模式能补好几天没跑的数据吗?

能补上「每只股票从最新日期到今天」的缺口,但它是按日期整体删除后重写的;如果缺的是较长的历史区间,用回填模式更合适,因为它逐只从断点续拉并跳过已入库股票。选择依据见排障续传页的决策表。

cron 里跑没反应怎么办?

先看有没有重定向日志文件:命令结尾必须有 >> log.txt 2>&1,否则输出直接丢失。其次确认三件事:是否先 cd 到项目目录、是否用虚拟环境里的解释器、.env 里的必填 Webhook 是否已配置。三项都对仍无输出时,看退出码是否为 1。

跑完一次要等多久才算异常?

README 自述日常约 2~3 分钟、回填约 12 分钟,但这是项目自述值,实际取决于机器、网络与待补数量。判断是否卡住的更可靠依据是日志是否还在推进(每 500 只的进度行、每条策略的结果行)。长时间无新日志时按排障页逐项核对。

非交易日或重复运行会重复推送吗?

会。增量写入为 0 条时源码只记一行日志(例如「所有股票已是最新,无需更新」或「无新数据」),随后仍会继续执行全部策略并推送命中结果。源码里没有「当天已推送就跳过」的判断,所以周末手动重跑会重复收到与上一个交易日相同的卡片。这是读 main.py 与 data/engine.py 得出的结论,具体以官方源码为准。

盘中运行会不会把没收盘的 K 线写进库?

存在这个风险:增量查询的结束日期是 date.today(),盘中运行时当日 K 线可能还没走完。补救很简单——收盘后再跑一次,源码在写入前会先 DELETE FROM stock_daily WHERE date = ? 当日记录再追加,可以覆盖掉不完整的那一根。建议把定时固定在工作日收盘后。

数据进来了,接着看结果怎么推

日常运行的终点是飞书卡片:哪个策略推给哪个群,由 webhook 路由决定。