candidate-pool 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,51 @@
2
2
 
3
3
  所有变动按 **Conventional Commits** 约定分类,由 `changelogen` 自动生成。
4
4
 
5
+ ## v3.0.2
6
+
7
+ [compare changes](https://github.com/GuoSirius/candidate-pool/compare/v3.0.1...v3.0.2)
8
+
9
+ ### 🐛 缺陷修复 (Bug Fixes)
10
+
11
+ - Code review 必改项修复(正则剥前缀、迁移标记、keep-alive、默认双写、ua与waf防护、engines) ([4955417](https://github.com/GuoSirius/candidate-pool/commit/4955417))
12
+
13
+ ### 📚 文档 (Documentation)
14
+
15
+ - 目录整理与定时任务真值源重建 ([b3a61ed](https://github.com/GuoSirius/candidate-pool/commit/b3a61ed))
16
+ - 收紧文档序号(05-复盘改03、npm-publish 02/03改01/02),同步全部引用 ([1b82665](https://github.com/GuoSirius/candidate-pool/commit/1b82665))
17
+
18
+ ### 📦 杂项维护 (Chores)
19
+
20
+ - 每日实时初筛 2026-10-22 ([f515912](https://github.com/GuoSirius/candidate-pool/commit/f515912))
21
+ - 盘前选股归档 2026-10-22 ([ad3936e](https://github.com/GuoSirius/candidate-pool/commit/ad3936e))
22
+
23
+ ### ❤️ Contributors
24
+
25
+ - 郭之存 ([@siriusSupreme](https://github.com/siriusSupreme))
26
+
27
+ ## v3.0.1
28
+
29
+ [compare changes](https://github.com/GuoSirius/candidate-pool/compare/v3.0.0...v3.0.1)
30
+
31
+ ### 🚀 新功能 (Features)
32
+
33
+ - **preopen:** 归档补贴线样本与淘汰统计支撑日后调参 ([c8d206b](https://github.com/GuoSirius/candidate-pool/commit/c8d206b))
34
+ - 次日候选快照记录当时规则常量与生成时间 ([3cc1b72](https://github.com/GuoSirius/candidate-pool/commit/3cc1b72))
35
+
36
+ ### 📚 文档 (Documentation)
37
+
38
+ - **eod:** 尾盘原始存档永久保留策略落注释并补复盘第8.6节 ([6ba4fef](https://github.com/GuoSirius/candidate-pool/commit/6ba4fef))
39
+
40
+ ### 📦 杂项维护 (Chores)
41
+
42
+ - **eod:** 尾盘口径版本号升到 2 并写明版本切段规则 ([5a6921a](https://github.com/GuoSirius/candidate-pool/commit/5a6921a))
43
+ - Obs run 2026-10-22 (0 candidates) ([4d44623](https://github.com/GuoSirius/candidate-pool/commit/4d44623))
44
+ - 尾盘选股 2026-10-22 ([2e0e85b](https://github.com/GuoSirius/candidate-pool/commit/2e0e85b))
45
+
46
+ ### ❤️ Contributors
47
+
48
+ - 郭之存 ([@siriusSupreme](https://github.com/siriusSupreme))
49
+
5
50
  ## v3.0.0
6
51
 
7
52
  [compare changes](https://github.com/GuoSirius/candidate-pool/compare/v2.2.0...v3.0.0)
package/build_universe.js CHANGED
@@ -23,6 +23,9 @@ const path = require('path');
23
23
  const https = require('https');
24
24
  const { now } = require('./time');
25
25
  const paths = require('./paths');
26
+ // UA 与 WAF 嗅探与主流程同源:残缺 UA(裸 "Mozilla/5.0")本身就是风控指纹特征;
27
+ // WAF 跳转页若不识别会静默「少抓几只」,必须显式报错(2026-10-22 code review #8)。
28
+ const { looksLikeWaf, UA } = require('./eod/lib/http');
26
29
 
27
30
  // 输出跟随工作目录(见 paths.js):默认 <仓库根>/candidates.json
28
31
  const OUT = paths.candidatesFile();
@@ -114,7 +117,7 @@ function getRaw(url, retries = 3) {
114
117
  return resolve(await new Promise((res, rej) => {
115
118
  const req = https.get(url, {
116
119
  timeout: 20000,
117
- headers: { 'User-Agent': 'Mozilla/5.0', 'Referer': 'https://gu.qq.com/' },
120
+ headers: { 'User-Agent': UA, 'Referer': 'https://gu.qq.com/' },
118
121
  }, r => {
119
122
  const chunks = [];
120
123
  r.on('data', c => chunks.push(c));
@@ -132,6 +135,9 @@ function getRaw(url, retries = 3) {
132
135
  async function fetchBatch(codes) {
133
136
  const buf = await getRaw('https://qt.gtimg.cn/q=' + codes.join(','));
134
137
  const txt = decodeGbk(buf);
138
+ // WAF 跳转页识别:命中的批次直接抛错(调用方按「失败」计数并打印),
139
+ // 而不是让正则静默匹配不到、把整批票当作「代码不存在」丢掉。
140
+ if (looksLikeWaf(txt)) throw new Error('被接口反爬拦截(WAF 跳转页),请稍后重跑');
135
141
  const out = {};
136
142
  for (const seg of txt.split(';')) {
137
143
  const m = seg.match(/v_([a-z]{2}\d{6})="([^"]*)"/);
package/db/clients.js CHANGED
@@ -18,16 +18,22 @@ const has = (argv, flag) => argv.includes(flag);
18
18
  *
19
19
  * | 参数 | 远程 D1 | 本地 db/local.db |
20
20
  * |-----------|----------------|------------------|
21
- * | (无) | 有凭据则写 | 不写 |
21
+ * | (无)本机 | 写 | 写(2026-10-22 起,与 ops/01 文档表格及尾盘 targetArgv 口径对齐) |
22
+ * | (无)CI | 写 | 不写 |
22
23
  * | --local | 不写 | 写 |
23
- * | --both | 有凭据则写 | 写 |
24
+ * | --both | 写 | 写 |
25
+ *
26
+ * 无显式参数时按「本机双写 / CI 只远程」取默认(判据 GITHUB_ACTIONS,
27
+ * 与 eod/lib/store_d1.js::targetArgv 同一口径)——此前本机裸跑只写远程,
28
+ * 导致本地库有尾盘数据却没有候选池快照,复盘缺半边。
24
29
  *
25
30
  * @param {string[]} argv 命令行参数,默认 process.argv
26
31
  * @returns {{targets: Array<{name: 'remote'|'local', client: object, file?: string}>, notes: string[]}}
27
32
  * notes 是需要调用方打印的提示(例如缺少远程凭据)。
28
33
  */
29
34
  function resolveTargets(argv = process.argv) {
30
- const wantLocal = has(argv, '--local') || has(argv, '--both');
35
+ const explicit = has(argv, '--local') || has(argv, '--both');
36
+ const wantLocal = explicit ? has(argv, '--local') || has(argv, '--both') : !process.env.GITHUB_ACTIONS;
31
37
  const wantRemote = has(argv, '--both') || !has(argv, '--local');
32
38
  const targets = [];
33
39
  const notes = [];
package/db/persist.js CHANGED
@@ -39,10 +39,12 @@ const BASE_Q = `INSERT OR IGNORE INTO stock_base (code,name,sector,updated_at) V
39
39
 
40
40
  // 惰性迁移:为既有 D1 / 本地 SQLite 补上 run_at 列(新库由 schema.sql 直接建好)。
41
41
  // 两端都会跑,先到者成功、后到者捕获「列已存在」忽略即可。
42
- let _migrated = false;
42
+ // 「已迁移」必须按 client 记(WeakSet)而非全局布尔:--both 时同一进程先后写
43
+ // remote + local 两个 client,全局旗标会让第二个库永远跳过 ALTER(静默缺列)。
44
+ const _migrated = new WeakSet();
43
45
  async function ensureColumns(client) {
44
- if (_migrated) return;
45
- _migrated = true;
46
+ if (_migrated.has(client)) return;
47
+ _migrated.add(client);
46
48
  for (const sql of [
47
49
  'ALTER TABLE pick_record ADD COLUMN run_at TEXT',
48
50
  'ALTER TABLE pick_record ADD COLUMN vol_ratio REAL',
package/db/write_live.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
  // 实时入库:读取「最近一次」快照,写入
3
- // Cloudflare D1(默认,不写本地)/ 本地 SQLite(--local)/ 两边都写(--both)。
3
+ // 本机裸跑默认双写(远程 D1 + 本地 SQLite,2026-10-22 起与尾盘口径一致);
4
+ // CI(GITHUB_ACTIONS)默认只写远程;--local / --both 可显式覆盖。
4
5
  // 由 run_today.cmd/sh 在 gen_candidates 之后链式调用 —— 本机任务用 --both,
5
6
  // 这样一次运行就让本地库与线上库同时前进,不会出现「一边新一边旧」。
6
7
  // 凭据缺失或入库失败时:打印告警并退出 0(不阻断报告生成本身)。