# Fund Forecast **Repository Path**: BANPAI82/fund_forecast ## Basic Information - **Project Name**: Fund Forecast - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-15 - **Last Updated**: 2026-09-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 基金涨幅预估工具 输入基金代码,推算该基金**当日的预估涨幅**。零第三方依赖,含桌面小窗、常驻采集服务与命令行工具。 ## 三种用法 | 场景 | 命令 | 说明 | | --- | --- | --- | | 看盘 | 双击 `启动.bat` | 打开桌面小窗,手动查询 | | 长期运行 | 双击 `启动服务.bat` | 常驻后台,盘中每 5 分钟自动采样,收盘后自动结算 | | AI / 脚本调用 | `python fund.py get --json` | 结构化输出,便于程序解析 | ## 命令行工具 ``` python fund.py start 启动后台采集服务 python fund.py stop 停止服务 python fund.py status 运行状态(进程、心跳、数据量) python fund.py add 001595 110022 新增基金到采集池 python fund.py remove 001595 移除 python fund.py list 列出基金池 python fund.py get --json 获取全部基金预估(AI 用) python fund.py get 001595 查询单只 python fund.py get --cached 读库中最新记录,不发起实时请求 python fund.py history 001595 历史预估与真实对照 python fund.py accuracy --json 精度报告:平均误差与改善幅度 python fund.py calib --json 校准参数:缩放系数、偏差、样本数 python fund.py export 001595 导出历史 CSV python fund.py settle 手动触发结算 python fund.py snapshot 导出种子文件(供 git 备份) python fund.py restore 从种子文件恢复 ``` 所有命令都支持 `--json`,输出形如: ```json { "ok": true, "market": {"status": "trading", "label": "盘中交易"}, "items": [{ "code": "001595", "name": "天弘中证银行ETF联接C", "estimatePct": -1.196, "estimateNav": 1.8019, "modelHoldingPct": -0.639, "modelBenchmarkPct": -1.264, "modelFactorPct": -1.213, "weights": {"benchmark": 0.666, "factor": 0.229, "holding": 0.105}, "confidence": 91, "calibration": {"samples": 30, "enabled": true, "maeBefore": 0.0125, "maeAfter": 0.0101} }] } ``` ## 后台服务 `启动服务.bat` 会用循环守护方式运行 `daemon.py`:**daemon 崩溃后 5 秒自动重启**。 停止请运行 `停止服务.bat`(写停止标记 + 终止进程 + 让守护循环退出)。 服务行为: - **盘中**(9:30-11:30、13:00-15:00)每 5 分钟采集一轮基金池全部基金 - **收盘后**每 30 分钟尝试结算一次,真实净值一旦公布就自动比对、写入误差并刷新校准参数 - **异常隔离**:单只基金失败只记日志,不影响其他基金,也不会终止进程 - **心跳**:每 10 秒刷新 `data/daemon.heartbeat`,`status` 命令据此判断是否卡死 ## 数据持久化 所有数据存于 `data/fund.db`(SQLite,标准库自带),开启 WAL 模式,每次写入即时提交。 **进程被强杀也不会丢数据**——已实测:写入 128 条记录后 `taskkill /F` 强制终止, 重启后记录数、基金池、校准参数完全一致,`PRAGMA integrity_check` 返回 `ok`。 四张表: | 表 | 内容 | | --- | --- | | `funds` | 基金池(代码、名称、类型、启用状态、备注) | | `estimates` | 每次预估记录(三路结果、权重、置信度),结算后回填真实涨幅与误差 | | `calibration` | 每只基金的校准参数缓存 | | `run_log` | 运行日志,保留最近 2000 条 | ### 数据备份与迁移 数据库是二进制文件,不适合直接进版本库。用文本种子代替: ``` python fund.py snapshot # 导出基金池 + 已结算样本到 data/seed.json python fund.py restore # 从 seed.json 恢复到当前库 python fund.py sync # 双向合并(多机协作推荐) python fund.py git-sync # 合并并提交推送到 git(守护进程自动做的就是这个) python fund.py inspect # 核对库内样本构成,排查多机数据差异 ``` `data/seed.json` 是纯文本(每条约 200 字节),可直接提交 git。 **库为空时会自动从种子恢复**,所以换机器、重装、删库后只要保留这个文件就能无缝续用, 在别的环境克隆仓库后启动即带上了全部历史样本与校准参数。 **导出与提交都是自动的**,正常使用不需要做任何事: - 守护进程启动时对一次账 - 每次收盘结算到新样本后:**先与远程仓库合并 → 再导出 → 提交 → 推送** - 手动执行 `fund.py settle` 或 `fund.py git-sync` 时同样 自动同步的安全设计: 1. **先保数据再提交**:种子里的记录一定先合并进本地库,之后才动 git。 所以哪怕 pull 或 push 失败,样本也不会丢,下次结算重试即可 2. **冲突不硬来**:`git pull` 失败(冲突或网络问题)就中止本次同步并记日志, 不会强制覆盖任何一方的数据 3. **无变化不空提交**:样本内容没变时不会产生多余的 commit 4. **推送失败只记日志**:本地提交仍然保留,下轮结算会再次尝试推送 想改成"只写文件、由人工提交",把 `config.py` 里的 `AUTO_GIT_SYNC` 设为 `False` 即可。 ### 多台机器之间合并样本 `seed.json` 是整文件覆盖的,两台机器各自 `snapshot` 会互相盖掉。要合并用 `sync`: ``` git pull # 先拿到另一台机器的更新 python fund.py sync # 合并:种子里的补进本地,本地的补进种子 git add data/seed.json git commit -m "chore: 合并校准样本" git push ``` `sync` 等价于 `restore` + `snapshot`:先按「代码 + 日期 + 时刻」去重导入种子中 本地缺失的记录,再把本地全部样本导出。所以两边积累的数据都不会丢。 > 注意 `seed.json` 是单个文件,两台机器同时 push 会冲突。 > 建议固定由一台机器(比如服务器)负责提交,或者在 push 前先 `git pull` 再 `sync`。 ## 桌面小窗 双击 `启动.bat`。会自动拉起本地服务并打开一个独立小窗, **那个黑色命令行窗口必须保持开启**,关掉它服务就停了。 > bat 优先使用 WorkBuddy 自带的 Python;若你本机装了 Python, > 把文件里的 `MGR=` 改成你的 `python.exe` 路径即可。 ## 启动失败怎么办 先跑自检,它会逐项检查并给出结论: ``` python main.py --check ``` 常见问题: | 现象 | 原因与处理 | | --- | --- | | 提示 Python not found | 未安装 Python,或 `python` 指向 Microsoft Store 存根。改用 `启动.bat`,或编辑 bat 里的 `MGR=` | | 端口被占用 | 程序会自动改用 8771-8781;若 8770 上已有本工具在跑,会直接复用并打开已有窗口 | | 小窗没弹出来 | 程序会自动退回默认浏览器打开标签页;也可手动访问 http://127.0.0.1:8770 | | 中文显示乱码 | bat 已切到 UTF-8 代码页;手动运行时先执行 `chcp 65001` | | 窗口一闪而过 | bat 末尾有 `pause`,不会自动关闭;若确实闪退,把 bat 拖到已打开的 cmd 里回车执行,可看到完整报错 | 自检输出示例: ``` Python 版本 : 3.13.14 页面目录 : 正常 8770 端口 : 空闲 浏览器 : C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe 实时行情 : 正常 沪深300 基金档案 : 正常 天弘创业板ETF联接C 历史日线 : 正常 181 条 ``` ## 能查什么 | 类型 | 示例代码 | 预估方式 | | --- | --- | --- | | 场外主动基金 | 110022、001593 | 持仓加权法 + 基准指数法 | | 场外指数/联接 | 001593、161725 | 基准指数法为主 | | 场内 ETF / LOF | 510300、159915、161725 | 直接采用实时成交价涨跌幅 | 支持一次输入多只,用逗号分隔。 ## 三路模型怎么算的 **路 A · 持仓加权法** 取基金最新披露的前十大重仓股(含权重),叠加各自实时涨跌幅加权求和; 未披露的部分用中证全指补齐。缺点:持仓是季报,滞后 1-3 个月。 **路 B · 基准指数法** 解析基金的跟踪标的 / 业绩比较基准,取对应指数的实时涨跌幅,再乘以估算权益仓位。 **路 C · 因子回归法(关键)** 取基金最近 120 个交易日的净值收益率,先按相关性从 36 个因子(宽基/行业/境外)里挑出最相关的 14 个, 再做**带非负约束的岭回归**,反推出该基金当前的真实暴露(不需要季报,能自动跟踪调仓)。 ## 自动修正是怎么做到的 1. **动态权重**:三路各自在过去 30 天做滚动样本外验证,按实测 RMSE 的反比分配权重。 指数基金会自动偏向基准法,主动基金会偏向因子法。 2. **误差校准**:每次预估都写入数据库;等真实净值公布后自动比对, 拟合出缩放系数与偏差,反哺修正后续预估。 3. **冷启动回填**:首次查询某只基金时,用因子模型滚动验证产生的 30 条样本外预测 直接填充校准库,第一天就有修正能力,之后逐步被真实样本替换。 4. **置信度**:直接由实测 RMSE 换算,不再靠拍脑袋打分。 ## 实测精度 运行 `python backtest.py` 可随时复现(窗口为过去 30 个交易日,单位:百分点): | 基金 | 零预测 | 基准法 | 因子法 | 等权融合 | | --- | --- | --- | --- | --- | | 000961 天弘沪深300联接 | 0.643 | 0.016 | 0.040 | 0.025 | | 001593 天弘创业板联接C | 1.417 | 0.011 | 0.027 | 0.016 | | 161725 招商中证白酒 | 1.160 | 0.105 | 0.127 | 0.112 | | 110022 易方达消费行业 | 0.768 | 0.326 | 0.390 | 0.343 | | 519674 银河创新成长 | 2.075 | 1.208 | 0.566 | 0.795 | | 110011 易方达优质精选 | 0.582 | 0.802 | 0.287 | 0.469 | | **平均(8 只)** | **1.007** | **0.418** | **0.279** | **0.313** | 指数型基金误差可压到 0.03 以内,主动基金约 0.3-0.6。 实际使用时按误差动态加权,通常优于表中的等权融合。 ## 接口限流与容错 腾讯行情接口对突发并发很敏感,请求过频会返回 **501**(不是常见的 429)。 一旦被限流,因子日线全部取不到,因子模型会整条失效、退化成两路估算。 为此做了四层防护: 1. **因子数据进程内只加载一次**:多只基金并发估算时共享同一份因子, 否则 4 只基金 × 36 个因子 = 144 次请求,必然触发限流 2. **日线缓存放宽到 4 小时并跨天失效**:日线是历史收盘数据,盘中不会变化, 当天取到一次即可长期复用,不必每半小时重取一遍 3. **分批加载**:每批 6 个、批间隔 0.5 秒、并发 3,避免瞬时并发 4. **启动预热**:守护进程启动时先把因子加载完,再进入采集循环, 避免首次采集与因子加载同时发起、请求叠加 5. **限流退避**:遇到 429/500/501/502/503/504 时,等待时间是普通重试的 4 倍 6. **失败冷却**:因子全部取不到时进入 180 秒冷却,不再每轮都重新冲击接口 7. **失败回退缓存**:日线请求失败就沿用上次成功的结果, 不会因为一次抖动让整个因子模型失效 实测:4 只基金并发估算的 K 线请求由 144+ 次降至 36 次(每天一两次全量刷新), 缓存命中后为 0 次;清空缓存后首次加载 4.9 秒完成,无限流。 ## 数据来源 - 实时行情:腾讯行情接口(A 股 / ETF / 指数 / 港股 / 美股) - 基金档案:天天基金 pingzhongdata、F10 基金概况 - 基金持仓:天天基金 F10 股票投资明细 - 历史净值:pingzhongdata 提供长序列(用于因子拟合); **当日净值与结算改用 F10 历史净值接口**,因为它比 pingzhongdata 更新更早—— pingzhongdata 的净值存在延迟,不同基金披露时间不一,曾导致当天无法结算 > 天天基金官方「净值估算」功能已于近期下线(估值接口返回 404), > 因此本工具不含官方估值,两路结果均为自建模型推算。 ## 目录结构 ``` config.py 全局配置 fund.py 命令行工具(AI 可调用) daemon.py 常驻采集守护进程 backtest.py 精度回测 core/ storage.py SQLite 持久化(基金池/预估/校准/日志) http.py HTTP 封装(重试/编码/JSON 片段提取) models.py 数据模型 code_util.py 基金代码识别与行情代码转换 quote.py 实时行情 archive.py 基金档案 holdings.py 持仓明细 history.py 历史净值与因子日线(带磁盘缓存) regression.py 岭回归/非负最小二乘(纯标准库) factor.py 因子暴露拟合与滚动验证 calibration.py 预估日志与误差校准 index_map.py 指数/基准匹配 estimator.py 三路融合估算引擎 service.py 批量编排与缓存 server/app.py 本地服务与 API web/ 页面(HTML/CSS/JS) data/index_map.json 指数名称到行情代码的映射(可自行扩展) data/fund.db 数据库(自动生成) ``` ## 扩展指数映射 若某只基金匹配不到跟踪指数,`data/index_map.json` 中补一行即可: ```json "中证白酒": { "symbol": "sz399997", "name": "中证白酒", "alias": ["白酒"] } ``` `symbol` 为腾讯行情代码;`proxy: true` 表示用 ETF 代理该指数;`alias` 用于模糊匹配。 ## 已知局限 - 因子模型用 120 天窗口,基金若刚发生大幅调仓,约需 1-2 周才能跟上 - 主动基金误差普遍在 0.3-0.6 个百分点,重仓股剧烈波动时会更大 - QDII 基金因跨时区、净值延迟披露,精度低于境内基金 - 不判断法定节假日,交易时段按周一至周五 9:30-15:00 粗略判定 - 校准样本需要积累:查询同一只基金的次数越多,修正越贴合该基金的实际偏差