shy3130
54ef03ac7d
fix(settings): 能力矩阵漏传全量分钟路由偏好, 卡片恒显不可用
2026-09-11 23:49:29 +08:00
wshy
a90c12b3a5
Merge pull request #299 from kevin9327/fix/ext-data-rows-date-guard
...
fix(ext-data): rows 的 date 入参先校验再拼分区路径
2026-09-11 09:02:26 +08:00
kevin9327
79eb150de2
fix(ext-data): rows 的 date 入参先校验再拼分区路径
...
`_read_ext_dataframe` 把 `date` 查询参数原样拼进 `timeseries/date=<值>`, 未经校验,
于是 `date=x/../../../../kline_daily` 读到的是 `ext_data/<id>/timeseries/` 之外的
`part.parquet` 并从 /rows 返回。同一文件的 /sync、/ingest、/backfill 都先
`date.fromisoformat` 再用, 只有这条读取路径没有。
拼路径前规范成 YYYY-MM-DD, 非法值按本文件既有约定返回 400。合法日期、
分区不存在、不传 date 三种情况的行为不变。
2026-09-11 00:50:33 +09:00
kevin9327
40c2468cbc
fix(screener): 涨停梯队的时序扩展列只取最新分区, 不再放大行数
...
ext_{config_id} 视图对 timeseries 模式覆盖 timeseries/**/*.parquet 全部分区
(app/api/ext_data._refresh_views), 一只票在 N 天快照里就有 N 行。梯队直接
LEFT JOIN 该视图, 同一只涨停股被复制 N 份, 各档 count 一并放大 N 倍。
改为与自选股列表 (app/api/watchlist) 同口径: 有配置时走 _read_ext_dataframe
取最新分区, 再按 symbol 去重后 JOIN; 无配置时保留视图查询兜底。
2026-09-10 19:35:32 +09:00
kevin9327
3f9c6da7dd
fix(ext-data): 卡片「最新」时间按北京墙钟, 不再随服务端时区漂移
...
扩展数据页同一张卡片上两个时间对不上: 底部「最新」显示 10:30:00, 而设置
里拉取面板的「上次」显示 18:30 —— 说的是同一次同步。Docker 镜像默认 UTC,
差的正好是一个时区。
latest_sync_date 由 parquet mtime 经 datetime.fromtimestamp(mtime) 格式化,
拿的是宿主机时钟, 且不带时区后缀; 前端 ExtDataStatCard 原样展示这串裸时间,
没有任何换算余地。旁边的 pull.last_run/next_run 是 datetime.now(timezone.utc)
的带偏移 ISO, 前端 new Date(iso) 按浏览器时区渲染, 所以那一侧是对的。
快照与时序两条路径都改成 fromtimestamp(mtime, tz=CN_TZ), 与
json_report_store._now_iso「用北京墙钟而非宿主机时钟」同口径。
展示格式不变。
2026-09-10 08:19:30 +09:00
shy3130
6345eb93ab
fix(strategy): 渐进式 run_all 逐策略隔离失败
...
单个策略执行崩溃 (如自定义策略 filter_history 的数据类型错误) 会杀掉
整批剩余策略: handle 整体 fail, 后台线程结束, 页面剩余卡片永远不亮。
线上实证: 70 策略池跑到第 35 个 (custom_1782999589 pl.DataFrame 构造
schema 混杂) 崩溃, 后 36 个全部没算。
改为单策略 try/except: 失败记入 handle.errors 并移出待算队列, 其余
策略照常算完落缓存; 响应新增 errors 字段 (前端可忽略)。job 级失败
(context 构建崩溃) 仍走整体 500 语义不变。
2026-09-09 15:49:21 +08:00
shy3130
01347b72bc
perf(strategy): 渐进式 run_all 只构建一次共享矩阵
...
_run_all_progressive 逐策略调用 engine.run_all(strategy_ids=[sid]),
run_all 不回写 context.market → 每个 matrix_native 策略都重建一次
全市场矩阵 (39 万行, 小服务器单次数秒到十余秒), 6 策略一轮多耗约
1 分钟。
从 run_all 抽出 build_shared_matrix (字段并集语义不变, 非渐进路径
行为一致), 渐进式循环外一次建好放入 context.market 复用。
2026-09-09 15:30:10 +08:00
shy3130
8d8b66c7f8
fix(kline): 分钟批量补全识别前部空洞, 重启跨开盘后分时可自愈
...
盘中重启/停机跨开盘后, 本地当日分钟K只剩重启时刻起的连续尾巴。
缺口判定只检查相邻K间隔, 连续尾巴被判"仅尾部落后"走增量 — 增量
锚定本地最新时间, 永远不会回看缺的开头, 上午的洞永久残留, 自选
分时只显示几根K。
- _has_holes 增加前部洞判定: 当日首根 > 开盘+6min 容差即视为洞,
归入全天重拉 (取到即落盘, 一次自愈)。仅根数不足的分支才判定,
稳态零额外请求; 停牌晚开票命中亦幂等无害
- 全量分钟服务健康时不再压制空洞类补拉 (服务增量补不了洞),
纯尾部落后的压制维持不变
实测: 服务器重启窗口后策略页(本地为空)走全天拉取显示完整、
自选页(有连续尾巴)被增量锁死只显示 11 根, 修复后统一自愈。
2026-09-09 12:13:04 +08:00
wshy
3db7f38446
Merge pull request #281 from 0112020179/codex/fix-enriched-refresh-memory
...
fix(oom): 降低补算内存峰值并统一重任务并发控制
2026-09-09 11:36:22 +08:00
0112020179
771a95a6d1
fix(oom): 降低补算内存峰值并统一重任务并发控制
2026-09-09 11:09:48 +08:00
wshy
5ffe43d42d
Merge pull request #280 from kevin9327/fix/backtest-stream-date-400
...
fix(backtest): SSE 端点非法 start/end 返回 400 而不是 500
2026-09-09 09:04:52 +08:00
wshy
efd9f820d4
Merge pull request #279 from kevin9327/fix/screener-run-all-as-of
...
fix(screener): run_all 的 as_of 与 /custom、/preset 同口径校验 (数字 as_of 会写坏策略缓存)
2026-09-09 09:04:46 +08:00
wshy
6eb1508fd8
Merge pull request #278 from kevin9327/fix/alerts-query-bounds
...
fix(alerts): 触发记录查询的 days/limit 补上范围约束 (limit=-1 静默丢记录)
2026-09-09 09:04:40 +08:00
wshy
fe1410532f
Merge pull request #275 from kevin9327/fix/factor-delete-fail-closed
...
fix(factors): 删除因子被拒绝时定义已被删掉 (删除路径未 fail-closed)
2026-09-09 09:04:22 +08:00
kevin9327 and Claude Opus 5
68005c92e6
fix(alerts): 触发记录查询的 days/limit 补上范围约束
...
GET /api/alerts 的 days、limit 是裸 int,没有任何约束,越界值不报错而是
静默返回错误结果:
- days=-1 → cutoff 被推到未来,200 但 alerts 为空(total 仍是 3)
- limit=-1 → out[:limit] 变成负数切片,3 条记录只返回 2 条,
静默丢掉最旧一条,调用方无从察觉
- limit=0 → 200 但 alerts 为空
同类列表端点已有正确写法:abnormal.py 用 `limit: int = Query(500, ge=1,
le=2000)`,rps.py 用 `days: int = Query(12, ge=7, le=30)`,越界直接 422。
本次把 /api/alerts 补齐到同一口径,上下限取存储侧保留策略本身
(alert_store.MAX_DAYS / MAX_RECORDS),不新增常量,超出保留窗口的请求
本来也没有可返回的数据。
前端 alertsList 实际只传 days=7、limit=1/10/500,全部落在新区间内;
新增的 tests/test_alerts_query_bounds.py 同时锁住这些合法取值仍返回 200
且记录条数不变。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-09-09 07:37:17 +09:00
kevin9327 and Claude Opus 5
fd5d883c8f
fix(screener): run_all 的 as_of 与 /custom、/preset 同口径校验
...
/api/screener/run_all 收的是无类型 dict,as_of 只在 isinstance(str) 时才
解析,其余类型原样透传,造成两个问题:
1. 非法字符串("not-a-date"、"2026-13-01")抛未捕获 ValueError → 500;
2. JSON 数字({"as_of": 2026})不进解析分支,直接被当作日期用下去。
实测:{"as_of": 2026} 返回 200,响应 as_of="2026",
strategy_cache.json 也写入 as_of="2026"({"as_of": 20260904} → "20260904")。
其它入口写进同一份缓存的是 "2026-09-04",cached-summary /
cached-result 都按 as_of 字符串比对,格式不一致的缓存条目永远失配。
同一份 as_of 在 /api/screener/custom 和 /api/screener/preset 上走
Pydantic 模型(CustomRequest / PresetRequest 的 `as_of: Optional[date]`),
非法字符串和数字都会被 422 拦下;只有 run_all 这一处漏了。本次把 run_all
补齐到同一口径:非字符串直接 400,非法字符串 400「日期格式错误」。
补 tests/test_screener_run_all_as_of.py,同时锁住合法 as_of 仍然照常执行、
缓存仍写 ISO 日期,以及不传 as_of 时回退到 latest_date()。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-09-09 07:36:21 +09:00
kevin9327 and Claude Opus 5
d2931aaadb
fix(backtest): SSE 端点非法 start/end 返回 400 而不是 500
...
strategy/stream、optimize/stream、walkforward/stream 三个端点直接裸调
date.fromisoformat(start/end),前端传入 "not-a-date"、"2026-13-01"、
"2026/09/04" 之类的值会抛未捕获 ValueError,客户端只拿到 500 和
Internal Server Error,看不到是哪个参数不合法。
仓库内同类入口已有正确写法:signals.py 的 /intraday/replay 把
date.fromisoformat 包在 try 里返回 400「日期格式错误」,mining.py 的
MiningRunRequest 用 field_validator 走 422。本次只把 backtest 这三处
补齐到同一口径,不改其它行为。
补 tests/test_backtest_stream_date_guard.py:三个端点 × 非法 start/end
断言 400;另外用服务端范围保护(backtest_range_guard)让事件流立即收尾,
断言合法日期照旧返回 200,证明不是把入口收窄。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com >
2026-09-09 07:35:32 +09:00
kevin9327
a49c8b3b15
fix(factors): 删除因子被拒时定义已被删掉
...
DELETE /api/factors/custom/{id} 的 404 守卫把 store.delete_one 当成存在性
探测, 但它会真的 unlink 文件并返回 True。当定义在盘上却没进注册表时
(load_into_registry 对注册失败的定义只告警跳过, 如复合因子的成员已被强制
删除), get_factor 为 None, 短路求值会走到 delete_one, 定义随即被删除。
随后的引用检查再返回 409「该因子仍有引用, 拒绝删除」—— 接口声称拒绝, 定义
却已经没了; 用户改带 force=true 重试只会得到 404, 定义无法恢复。
把 fail-closed 的引用检查移到存在性判定之前, 保证任何拒绝路径都不改磁盘。
2026-09-09 07:20:16 +09:00
kevin9327
e349f2ba9b
fix(settings): 端点测速在清单缓存未预热时 500
...
_endpoints_cache 初值是 {"ts": 0.0, "data": None}, "data" 键存在, 所以
dict.get("data", {}) 的默认值不生效, 返回的是 None。进程启动后到第一次
GET /api/settings/endpoints 之前, POST /api/settings/test_endpoint 不带
rounds 会在 None.get("testRounds", 5) 上抛 AttributeError → HTTP 500。
前端 endpoints 查询有 5 分钟 staleTime, 后端重启后用户再点测速正好落在
这个窗口: 前端不会重新拉清单, 后端缓存却已清空。
改为先 `or {}` 兜底再取 testRounds, 保持原有默认 5 轮语义。
2026-09-09 07:12:54 +09:00
0112020179
a8bb7a25bf
fix(kline): 压缩详情响应并限制无权限分钟回退
2026-09-08 18:09:59 +08:00
shy3130
908b385501
feat(ext-data): 拉取接口支持 API Key 鉴权 + 扩展数据弹窗加宽可滚动
...
后端:
- PullConfig 新增 auth (none/bearer/header/query, 与自定义行情源
AuthConfig 同口径); 拉取/测试/回补共用 _request_json, 鉴权注入
只有一套口径, 用户自定义 Headers 仍优先于 UA 标识头
- Key 本体存 secrets_store (data/user_data/secrets.json, 0600),
不落 config.json; EXT_{ID}_API_KEY 环境变量兜底; 配置了鉴权但
未设 Key 时 fail-closed 拒绝请求
- 新增 GET/PUT /api/ext-data/{id}/api-key (GET 只返回脱敏值);
删除配置时清理残留 Key; 历史 config.json 无 auth 字段读为 None
行为不变; PUT /pull 不带 auth 时沿用现有鉴权
前端:
- 拉取面板新增"接口鉴权"区块: 方式下拉 + 请求头名/参数名 + Key
密码框 (输入新 Key 覆盖, 清空保存删除), 随保存/测试/开关一起生效
- SettingsModal 加 width prop, 扩展数据设置弹窗与 EditExtDialog
加宽至 max-w-2xl; SettingsModal 加 max-h-[88vh] + 内容区独立
滚动, 矮视口下不再被截断
2026-09-07 22:54:05 +08:00
shy3130
f8a23b7ce5
fix(api): quote_service 缺失时 quote-interval 兜底返回默认档位 ( #261 )
...
PUT /preferences/quote-interval 的 if not qs 分支错误调用
qs.get_min_interval(),此时 qs 必为 None,触发 AttributeError → 500。
改为返回硬编码默认值 6.0,与 GET 接口兜底写法及
QuoteService.DEFAULT_INTERVAL 保持一致,并新增复现测试。
2026-09-07 22:01:12 +08:00
shy3130
f03bc38a16
feat(screener): run_all 渐进式返回, 快策略先出、慢策略后台补算
...
策略页全量 run_all 需 ~2 分钟, 期间卡片全空。现在按历史耗时升序执行,
首返时限 (strategy_run_all_first_return_s, 默认 15s) 内算完的策略随
响应返回, 慢策略转后台继续算并逐个写入策略缓存, 前端轮询
cached-summary 逐个点亮卡片数字 (未出的显示脉冲占位)。
后端:
- services/strategy_run_queue: 单飞 daemon 工作线程 + handle 状态。
相同 key (资产/周期/日期/策略集) 且未完成的请求搭车现有执行不重算;
已完成的重跑即新执行。后端全局同时只跑一个 run_all, 补上前端
防重入之外的第二道 Numba 并发防线
- run_all 渐进分支 (仅日线 + summary_only): 逐策略增量写缓存 (同日
按 sid 合并), 收尾整体重写保持旧口径; 结果带 computed_at 时间戳;
分钟周期与明细请求保持整段阻塞不变
- 历史耗时落盘 user_data/strategy_run_timings.json, 次日起快策略自动
排前; cached-summary 透传 computed_at
前端:
- 请求通用 30s 超时 + 慢接口豁免清单 (run_all/run/backtest/factor 等
300s), 避免一个挂起请求占满 HTTP/1.1 连接拖死全站
- Screener: 收到 pending 后 summaryQuery 每 2s 轮询, 以
computed_at >= started_at 判新 (防同日旧缓存冒充), 8 分钟兜底;
StrategyCard 三种尺寸新增 computing 脉冲占位
验证: 新增 13 测试 (排序/落盘/搭车/串行化/端点行为/旧路径兼容),
全量套件 1762 passed; pnpm build 通过。
2026-09-07 15:25:54 +08:00
shy3130
ddb265b0f8
feat(ext-data): 出站请求默认携带 tsp 标识头
...
扩展数据的三个出站点 (定时/手动拉取与历史回补、内置预设拉取、URL 探测
测试) 统一经 outbound_headers() 注入 User-Agent: tsp/<版本> 与
X-TSP-Client: tick-stock-panel, 服务端 (如 tickflow-hub) 可据此识别
本项目的请求来源。
用户在拉取配置里显式设置的同名请求头优先 (大小写不敏感匹配, 不重复
发送), 需要特定 UA 的数据源不受影响。
验证: pytest 22/22 (含 3 个新用例: 默认标识头/用户头优先/实际请求携带);
逐文件 ruff 与 HEAD 对比零新增。
2026-09-06 23:16:27 +08:00
shy3130
cd9e20610f
feat(ext-data): 时序表历史回补 — date_param 按日拉取 + tickflow-hub 404 契约
...
人气排行等 timeseries 扩展表此前只能从开启拉取之日起逐日累积。拉取配置
新增日期参数名 (date_param), 接口支持按日查询时即可历史回补: 按本地交易日
逐日请求 ?{date_param}=YYYY-MM-DD 写入对应分区, 幂等 (已有分区跳过),
单次上限 120 天, 429 限流退避重试 + 连续限流中止可续补。
适配 tickflow-hub PR#19 (/exports、/fuyao-rank 按日历史截面):
- 该日无快照返回 404 → 计入 empty 跳过, 不进失败清单 (主循环与 429
退避重试两条路径均覆盖)
- 防污染契约: 响应行 date 与请求日期不一致 (接口忽略日期参数) 时
fail-closed 拒写该分区, 避免当日值污染整个历史时序
- 修复调度器 next_run 计算的 UTC 未导入 NameError
前端拉取面板新增日期参数名配置与回补入口; 回补落盘的历史数据立即进入
信号/因子/回测按日对齐通道 (PIT)。
验证: pytest tests/test_ext_backfill.py 16 通过 (含 404/429/幂等/防污染),
ext 全套 144 通过; pnpm build 通过。
2026-09-06 22:35:08 +08:00
wshy
f275edafeb
Merge pull request #256 from SummerCaptain/feat/recap-push-gate
...
feat(preferences): 复盘推送 review_push_mode 门控
2026-09-06 20:53:29 +08:00
wshy
f0c0fd3bf8
Merge pull request #255 from SummerCaptain/feat/ai-strategy-draft-gate
...
feat(strategy): AI 策略保存为 research_only 草稿 + publish 端点
2026-09-06 20:53:25 +08:00
shy3130
e3a2fbce13
feat(ext-data): 扩展表字段接入信号与因子(数值因子/评分 + string 归属筛选)
...
数值字段(int/float) → 信号+因子双通道:
- ext_factors: 帧组装时 join 扩展列并注册 kind=base 因子(分组「扩展数据」),
时序模式按 (symbol,交易日) 精确对齐无未来函数, 快照模式仅当日单日帧
注入(历史帧跳过防未来函数)
- registry.all_factors 惰性同步(配置目录签名幂等, 以注册表为权威增删);
custom_signals.allowed_fields 自动并入 → 信号下拉/因子库/AI提示词/检验
同一份清单; factor 补算入口按需注入
- 失效链: 上传/拉取/配置变更自动清扩展帧缓存+策略缓存, API层补
repo.clear_cache; 写入后下一次计算立即生效
- 列名保留中文(预设表字段名), 非ASCII数值字段只进信号不注册因子
(DSL标识符ASCII-only)
string 字段(概念/行业归属) → 仅信号条件通道:
- 运算符 包含(contains,字面量匹配非正则)/等于/不等于, 右值为字符串字面量,
可与数值条件混合(强势板块归属 AND 热度阈值)
- 前端信号编辑器按字段类型切换运算符与右值输入; /options 暴露
stringFields; AI 提示词含字符串字段清单与 contains 用法
- string 不注册为因子(数值口径), 空值不误报
测试: test_ext_factors 18个(PIT对齐/跨日不泄露/快照门控/写入失效/
contains字面量/中文列名端到端等); 存量因子计数测试补 data/ 运行时隔离
夹具(黄金断言不依赖本机扩展表); 受影响回归148个全过; pnpm build 通过;
ruff 对齐 main 基线
2026-09-06 18:27:33 +08:00
shy3130
716897f41a
feat(signals): 信号库新增盘中信号(分钟K特征)
...
- intraday_features: 会话对齐特征帧构造器(vwap/涨跌幅/1·3·5分钟放量比/
日内与开盘30分钟高低点距离, 滚动窗口不跨午休, 只用已收盘bar防未来函数)
- custom_signals: timeframe=daily|intraday 双 schema, 盘中条件支持
cross_up/cross_down 穿越算子; 输出为当日条件上升沿(首bar不触发,
null特征判false绝不误报)
- 旧4个分时穿越信号列名零迁移(评估器回映射历史列名, 存量监控规则不动)
- 引擎单点注入 csgi_ 列: 监控/分钟策略/分钟回测共用同一构造器;
日线策略引用盘中信号显式报错
- 回放验证 API /api/custom-signals/intraday/replay(本地历史分钟K重放,
区间≤60天标的≤200, 先验证再配置监控)
- 能力门槛: 分钟K能力(订阅池)或全量分钟能力(本地分区); 回放仅需本地历史
验证: 新增16个测试(特征数值/边界/旧4信号黄金等价/引擎注入/回放端点),
受影响回归109个全过, ruff对齐基线, docs/features.md 同步
2026-09-06 18:26:29 +08:00
sc
9d55c237ed
feat(preferences): review_push_mode 端点与前端开关配套
...
- settings: GET 返回 review_push_mode, PUT review-push 支持 mode 入参
- market_recap: push 移入 SaveReportRequest body(显式外发)
- Review 页: 推送触发方式 auto/manual 开关
- 门控测试: 手动/定时两条路径的 manual/auto 推送断言
2026-09-06 16:20:42 +08:00
sc
e6c7fa4a43
feat(strategy): 策略池 AI 草稿分区与发布闸前端配套
...
- 后端 publish 失败由 ValueError 改为 HTTPException(500) 返回给前端
- 策略池 AI 标签新增「草稿」分区, 展示 research_only 策略并提供发布按钮
- 导入/保存 AI 策略为草稿时提示发布后可用, onSavedId 对草稿态跳过入池校验
2026-09-06 16:05:02 +08:00
sc
905fb8846c
feat(preferences): 复盘推送 review_push_mode 门控
2026-09-06 13:41:52 +08:00
sc
f6fc22fef1
feat(strategy): AI 策略保存为 research_only 草稿 + publish 端点
2026-09-06 13:41:51 +08:00
kevin9327
e12e0c7d02
fix(watchlist): 自选导入上传分块读取, 越限即拒绝而非读完再拒
...
import-csv / import-image 原先 `await file.read()` 之后才比较长度, 上限只在
整个文件进入内存之后生效, 与 issue #204 修复前的扩展数据上传同类。新增
_read_upload_capped 分块读取, 累计超过上限的那一块立即返回 400 并停止读取,
状态码与文案不变; 内存占用不超过上限 + 一块。
测试: 新增 5 例 (含「越限后不再继续读取」的字节计数断言); test_watchlist_csv
的上传 mock 改为像真实 UploadFile 一样读尽返回 b""。
2026-09-05 21:11:44 +09:00
shy3130
2ff909cd36
fix(notifications): #244 维护者补丁 — 移除预埋类型并修正全角标点
...
- 移除 api.ts 中与通知无关的 MainCostEstimate/StockLevels.main_cost 类型(对应后端字段在本仓库不存在, 属跨 PR 预埋, 全仓库零引用)
- settings.py 5 处 PR 新增字符串的全角逗号改半角, RUF001 恢复到 main 基线(28 ≤ 29)
- 验证: 通知测试 48 passed, 前端 build 通过
2026-09-05 17:16:58 +08:00
wshy
c1cad36449
Merge pull request #244 from yushenglin01/feat/notification-channels
...
feat(notifications): add custom webhook and email channels
2026-09-05 17:14:25 +08:00
shy3130
e0cd625ef4
feat(platform): 因子平台与因子↔策略双向联动 v0.2.3
...
- 因子平台: /factors 一级页(检验/因子库/编辑器/组合/挖掘), DSL 公式因子(25 算子点选、双语字段、我的因子模板、脏公式守卫), 版本与生命周期, 自动挖掘 L1 统计筛选
- 因子↔策略四条桥: 触发器 Zap 快建因子条件信号、因子一键生成排名策略、自定义信号 AI 提示词接入因子分组、策略回测因子归因(胜/败单入场信号日因子均值, 独立 tab, 双语因子名)
- 回测: 统计卡新增盈亏比(≥1 红/<1 绿), 蒙卡回撤合并为中位/95% 双值卡(自适应字号), 高级设置基础过滤与策略编辑器参数对齐(5 组区间)
- 信号库独立页 /signals(原设置 tab 迁出), 持仓提醒入导航; 挖掘并入因子页第 5 tab, /mining 旧链接重定向
- 研究线配套: 因子目录 61→77(评分/矩阵双内核), stats_v2(Newey-West/BH-FDR/DSR), enriched 管道与异动/报价服务配套调整
- 文档: README 导航与特性表、features.md 因子平台章节、操作说明书 9.2、factor-platform-plan 执行状态与 §5、二开文档桥接说明; 交流与支持节改版
- 版本 0.2.2 → 0.2.3; 后端全量 1625 passed(1 例环境性跳过), 前端 build 通过
2026-09-05 15:41:15 +08:00
yushenglin
5289cde13e
feat(notifications): add custom webhook and email channels
2026-09-04 16:37:06 +08:00
0112020179
8721bd2e83
perf(kline): update detail chart with latest row
2026-09-03 17:35:16 +08:00
shy3130
41205b197c
chore: follow-ups for PR #231/#233 reviews
...
- monitor_rules: raise from None in remind_date validation (B904)
- lots: log warning on asset-type fallback to stock (fail-open traceability)
- matrix: demote turnover NaN-column notice to debug
2026-09-03 12:45:24 +08:00
richard and Claude
adc7ab52a9
feat(lots): holdings-reminder registry with auto stop/profit & expiry monitoring
...
新增「持仓提醒」页(/lots),登记买入批次(个股/ETF),每批自动生成并同步两条
监控规则: lot_{id}_p(type=price 止盈止损)与 lot_{id}_d(type=date 到期提醒)。
- 核心监控引擎新增 date 规则类型: 纯日历窗口、每个交易日仅在首个轮询评估一次、
按天 cooldown、跨天清理过期键; 消息按触发当天显示"N天后到期/今日到期"。
- 批次派生规则继承默认 webhook 渠道; 监控中心只读展示(批次/批次托管徽标),
通用 monitor-rules 接口对带 lot_id 的规则写/删返回 409, 避免与批次页脱节。
- 通知正文统一在缺省时追加触发现价与涨跌幅, 并避免与引擎自带引语重复。
- 后端分层: strategy/lots.py 域(校验/存储/批次→规则纯映射) + api/lots.py 薄路由
(写锁/校验先行/级联删规则/复用 _sync_engine 重载); services/fs_utils.py 原子写。
- 前端: api/queryKeys 契约、DateShortcuts、Lots 页(数值输入可留空、加载/出错态、
文案打磨)、Monitor 日期提醒/批次徽标; RuleEditor 不手工建 date(由持仓页生成)。
- 记账/加仓减仓属"交易口径", 不在本改动(issue #230 ); 到期提醒按自然日窗口,
休市/节假日顺延的交易日历口径待 issue 定夺。
验证: 新增 tests/test_date_rule.py + tests/test_lots.py 全绿(20), 监控族回归通过,
ruff 新文件干净, pnpm build 通过。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-09-02 20:20:38 +08:00
wshy
a28f9e852f
Merge pull request #228 from thinkbuf/feat/watchlist-import-csv-groups
...
feat(watchlist): batch import CSV / pasted codes into groups
2026-09-02 15:55:18 +08:00
richard and Claude
e9f5c606b6
feat(watchlist): batch import CSV / pasted codes into groups
...
自选页新增批量导入:支持 CSV/TXT 文件与粘贴证券代码两种来源,解析出
候选并在弹窗内确认后按 M:N 分组一次性写入(目标分组可多选或就地新建,
默认只勾新增标的,已在自选的可并入所选分组)。
Co-Authored-By: Claude <noreply@anthropic.com >
2026-09-02 14:48:32 +08:00
richard and Claude
40fea3236e
feat(monitor): add webhook test message button
...
Add a test button to the push-notification settings so users can verify Feishu and WeCom group-webhook configs after saving.
Backend: POST /api/settings/preferences/webhook-test reads the saved webhook URL/secret and sends a one-shot test message (max_attempts=1 to skip production retry backoff). All failure modes return HTTP 200 + {ok:false, detail} so the UI renders a single path.
Frontend: api.sendTestWebhook(); TestSendButton/TestResult components shared by both channels; success feedback auto-dismisses after 2s.
Tests: 7 cases covering both channels, failure modes, and single-attempt behavior.
Co-Authored-By: Claude <noreply@anthropic.com >
2026-09-02 13:36:06 +08:00
shy3130
e8c870af73
Merge branch 'pr-219' into merge/pr-221-220-219
2026-09-01 22:20:01 +08:00
shy3130
a9c00fd567
Merge branch 'pr-221' into merge/pr-221-220-219
2026-09-01 22:20:01 +08:00
shy3130
95cd99ab8c
merge: 同步 main (辐射本地读 + 传输压缩/网络设置) 到全量分钟分支
...
冲突两处均为 minute-refresh status 字段两侧各自新增, 两者全保留
(healthy + provider/provider_effective/repair_only)。
2026-09-01 13:05:21 +08:00
shy3130
bc9461da9a
feat(net): 分时/日K批量响应可选 gzip 压缩与网络设置
...
- _gzip_payload: 偏好开启 + Accept-Encoding 协商 + 超 1KB 才压
(level 6); datetime 序列化与非压缩路径一致, 保证 since 增量
字符串字典序合并不受影响
- minute-batch / daily-batch 端点各自独立偏好键, 逐请求即时生效;
实测分时 9.1MB→1.28MB (86%), 日K 736KB→156KB (79%)
- 超时设置 tab 更名网络设置, 卡内新增压缩区: 大开关 OR 联动
(任一子开即亮, 全关才灭, 点击全开/全关) + 分时/日K两个子开关
- preferences.save() 加线程锁: 修复并行 PUT read-modify-write
互相覆盖 (总开关批量关不齐的根因), 存量偏好写入一并受益
- 测试: 双端点压缩/关闭直通/无协商头直通/偏好默认 + 并行 save 竞态
2026-09-01 13:04:00 +08:00
shy3130
010c484289
feat(data): 全量分钟 (full_minute) 数据集开放插件/自定义源接入
...
像其他能力一样可路由: 声明 full_minute 数据集并在设置页路由, 即接入
盘中全市场分钟落盘服务 (与 TickFlow Expert 同一能力键 intraday.universe)。
- policy: _DATASET_CAP_MAP 增补 full_minute → INTRADAY_UNIVERSE, 自定义源
声明且被路由时自动补授能力, 服务门控对两类源统一口径
- capabilities 注册表: full_minute 从不可路由 (field=None) 改为
full_minute_data_provider 偏好路由; preferences/settings API 收发新字段
- 插件契约: get_intraday_batch (修复轮, 未实现回退 get_minute 当日窗口) +
get_intraday_latest (稳态增量, 可选; 未实现降级仅修复轮, 节奏下限 60s)
- YAML 声明式源: full_minute 数据集与 minute 同形, loader 白名单放行,
源编辑器 UI 可配置; 仅修复轮语义
- kline_sync 边界: fetch_intraday_custom_batch / _fetch_intraday_custom_latest,
帧过北京墙钟守卫, 与 TickFlow 边界函数同纪律
- minute_refresh: 删「自定义分钟源让位」逻辑, 改按路由取数;
status 增 provider / provider_effective / repair_only
- 前端: 监控页卡片按能力驱动, 数据源页路由矩阵, api.ts 类型
- 测试: 门控/路由/降级/增广新增用例, 后端 1332 全过
- 文档: plugin-development / custom-data-source / configuration / features /
CONTRIBUTING 契约细化 (AI 可照文档接入)
2026-08-31 22:53:24 +08:00
shy3130
be799abfa0
fix(intraday): since 增量时区崩溃 — 客户端直传原始时间串, 服务端归一 aware 输入
...
客户端 toISOString 生成带 Z 的 UTC, Python 3.12 解析为 aware datetime,
与行内 naive 北京时间比较 TypeError (第二轮轮询 500), 且换算差 8 小时。
- 客户端: since 直接回传最旧最后一根的原始 datetime 字符串 (同格式同时区,
字典序即时间序), 消灭一切换算
- 服务端: fromisoformat 后 aware 输入先转北京墙钟再去 tzinfo, 防御旧客户端
2026-08-31 22:01:46 +08:00