Files
MoFin/CHANGELOG.md
知微 04b8a6d4bc mo_data: +write_cash_log 函数
cash_log表已存在,新增写入函数便于截图/交易变更时记录现金流水。
用于process_trade.py、手动改cash时调用,保证现金变更可追溯。

知识萃取-盘后 cron 已暂停(莫荷接手知识库报告)
2026-07-02 01:43:33 +08:00

319 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MoFin 架构改革 — 变更日志
> 日期:2026-06-29 ~ 2026-06-30
> 执行:Sisyphus (小小莫)
> 背景:total_assets 频繁计算错误(遗漏 frozen_cash)、币种混淆(CNY/HKD)、港股 15 分钟延迟
---
## 新增文件
| 文件 | 用途 |
|------|------|
| `mo_models.py` | 统一数据模型 —— `calc_total_assets()`, `is_hk_stock()`, `get_hk_rate()`, `to_cny()`, `validate_portfolio()` |
| `mo_provider.py` | DSA 数据源适配器 —— 包装 daily_stock_analysis 的 16 个 FetcherTDX 优先、DSA 自动 fallback |
| `mo_config.py` | 配置单例 —— 替代散落在 10+ 文件中的硬编码路径 |
| `mo_bridge.py` | DSA 集成桥 —— 从 DSA 获取大盘复盘/新闻,注入 MoFin 分析 prompt |
| `scripts/data_validate.py` | 数据自检脚本(知微创建) |
| `scripts/holdings_reconciliation.py` | 持仓一致性校验(知微创建) |
| `scripts/process_trade.py` | 成交处理脚本(知微创建) |
| `docs/portfolio-data-model.md` | 数据模型文档(知微创建) |
| `data_freshness.py` | 数据新鲜度校验(知微创建) |
## 修改文件
| 文件 | 变更 |
|------|------|
| `price_monitor.py` | ① 合并两处重复 total_assets 计算 → 统一调用 `mo_models.calc_total_assets()` ② is_hk_stock 检测切换为 `mo_models.is_hk_stock()` ③ HK_RATE 获取切换为 `mo_models.get_hk_rate()`**港股行情来源从腾讯 gtimg(15分钟延迟)切到东方财富 push2.eastmoney.com(实时)** |
| `server.py:960` | `total_assets` 公式补上 `frozen_cash` |
| `strategy_lifecycle.py:428` | `currency_utils`(不存在)→ `mo_models` |
| `scripts/stale_push_wlin.py` | ① is_hk_stock 统一走 mo_models ② lot_cost 去掉硬编码 0.866 ③ fallback total_assets 改为 mo_models |
| `scripts/stock_scorer.py` | `len(code)<=5` 误判 → `mo_models.is_hk_stock()` |
| `scripts/holdings_reconciliation.py:98` | total_assets 公式补上 frozen_cash |
| `scripts/import_holding_xls.py:93` | total_assets 公式补上 frozen_cash |
| `mo_bridge.py` | DSA 路径自动检测(服务器 /home/hmo/daily-stock-analysis |
| `mo_provider.py` | DSA 路径自动检测 + Tencent API 集成 |
## 服务器部署
| 操作 | 状态 |
|------|------|
| `git pull` 拉取最新代码 | ✅ |
| DSA 源码上传到 `/home/hmo/daily-stock-analysis/` | ✅ |
| DSA .env 配置(opencode-go 三 Key:新Key → 旧Key → Key3 | ✅ |
| `pip install` 安装 DSA 依赖(litellm, sqlalchemy, pandas, akshare 等) | ✅ |
| Python 语法检查(37 个文件) | ✅ |
| 实盘数据验证(total_assets=967712.85 零误差) | ✅ |
| 港股实时行情测试(8/8 全成功) | ✅ |
| DSA Web 服务启动(FastAPI + Swagger | ✅ |
### DSA Web 访问
- **地址**`http://192.168.1.246:8001`
- **API 文档**`http://192.168.1.246:8001/docs`Swagger 交互界面)
- **触发分析**`POST /api/v1/analysis/analyze`
- **开机自启**:已加入 crontab `@reboot`
> 注意:React 前端未构建(apps/dsa-web/ 未上传,需要 Node.js),目前只提供 API 服务和 Swagger 文档界面。 |
## 架构变化总结
**之前**
```
total_assets 在 6+ 个文件中各自计算,3 个漏了 frozen_cash
is_hk_stock 有 3 种不同实现,len(code)<=5 会误判深市A股
hk_rate 硬编码 4 个不同值(0.866/0.87/0.8664/0.8700
30+ 文件绕过 mofin_db 直接读写 JSON
港股走腾讯 gtimg.cn — 15分钟延迟
data_dir 在 10+ 个文件中各自硬编码
```
**之后**
```
total_assets → 唯一入口 mo_models.calc_total_assets(pf)
is_hk_stock → 唯一入口 mo_models.is_hk_stock(code)
hk_rate → 唯一入口 mo_models.get_hk_rate()API → 缓存 → 0.87 fallback
港股行情 → 东方财富 push2.eastmoney.com(实时,免费)
→ fallback: 腾讯 gtimg.cn15分钟延迟兜底)
DSA 数据源 → mo_provider16 Fetcher 自动 fallback
DSA 情报 → mo_bridge(大盘复盘注入 MoFin 分析)
配置路径 → mo_config(单例,不再散落)
```
## 待办(服务器端)
```bash
# 知微需要确认的:
# 1. 明天开盘后验证港股价格是实时的(不再滞后15分钟)
# 2. migrate_all.py 需要跑一次(补齐 stock_sector_map/watchlist/market_context 表)
cd /home/hmo/MoFin && python3 migrate_all.py
```
## 测试记录
- 语法检查:37/37 文件通过
- 导入链路:16/17 核心模块通过
- mo_models 自检:is_hk_stock 7 用例全通过、calc_total_assets 零误差
- 实盘验证:total_assets=967712.85 = stored 967712.85
- 港股实时:8/8 港股东方财富拉取成功
- DSA 集成:DataFetcherManager 加载成功(6 Fetcher
---
## 2026-06-30 — DSA Web + 选股链路 + 小果EasyTier
### DSA Web 界面上线
- DSA 完整源码上传到 `/home/hmo/daily-stock-analysis/`
- React 前端构建并部署(40个静态文件)
- FastAPI 服务运行在 `http://192.168.1.246:8001`
- Swagger API 文档: `http://192.168.1.246:8001/docs`
- 开机自启已加入 crontab
- 防火墙 8001 端口已开放
### DSA 三项功能对接 MoFin
| 功能 | 文件 | 说明 |
|------|------|------|
| 新闻搜索 | `mo_bridge.get_stock_news()` | DSA SearchService → akshare 东方财富 fallback |
| 大盘复盘 | `mo_bridge.get_market_review()` | 缓存优先(24h),cron 不阻塞 |
| 策略参考 | `mo_bridge.get_stock_analysis()` | 独立调用,`mo_dsa_opinion.py 00700 腾讯控股` |
| 策略注入 | `strategy_lifecycle.reassess_with_context()` | DSA 上下文自动追加到 MoFin 分析 prompt |
### DSA 策略注入
`strategy_lifecycle.py``reassess_with_context()` 中增加了 DSA 上下文注入:
- 自动识别港股/A股 → 选择对应区域大盘复盘
- `enrich_analysis_context()` 追加到 `macro_desc`
- DSA 不可用时静默跳过,不影响 MoFin
### AlphaSift 选股(默认关闭)
- AlphaSift 已安装(`pip install alphasift`
- 8 种策略可用
- `mo_alphasift_bridge.py` 支持多策略并行选股
- 默认关闭(`ALPHASIFT_ENABLED=false`
- 启用: `ALPHASIFT_ENABLED=true python3 mo_alphasift_bridge.py`
- 每条自选股记录包含:来源策略、评分、日期、因子得分、选股理由
### 原有选股链路修复
**问题**`market_watch.py``market_screener.py` 从未加入 cron,导致零产出。
**修复**
- `market_watch.py``market.json`90个板块,每30分钟更新)
- `market_screener.py` → 小果 LLM → `candidate_pool.json`(每30分钟)
- 已加入 crontab`*/30 9-15 * * 1-5`
### 小果连接统一(EasyTier 兼容)
**问题**5个文件硬编码 `192.168.1.122`,小果离开局域网后无法连接。
**修复**
- 全部改为 `node122`(机器名)
- `/etc/hosts` 配置:
- LAN: `192.168.1.122 node122`
- EasyTier VPN: `10.144.144.2 node122`
- 涉及文件:`market_screener.py`, `xiaoguo_scanner.py`, `xiaoguo_news_processor.py`, `intraday_health_check.py`, `ocr_client.py`
- `mo_config.py` 统一管理:`xiaoguo_host="node122"`, `xiaoguo_port=18003`
### 待办
```bash
# 知微需要确认:
# 1. 明天开盘验证 market_screener 产出有效候选股
# 2. 如需启用 AlphaSift: ALPHASIFT_ENABLED=true python3 mo_alphasift_bridge.py
```
- LLM 连通:opencode-go 三 Key 正常
---
## 2026-07-01 — DB 迁移 + 唯一价格源 + 保活机制
### JSON → DB 完整迁移(币种约束)
**4 张核心表加 `currency` 列**`NOT NULL DEFAULT 'CNY'`):
- `holdings` — 新增 price, market_value, change_pct, currency
- `holding_strategies` — 新增 15 列(currency, action, trigger_json, changelog_json 等)
- `portfolio_summary` — 新增 total_mv, frozen_cash, currency
- `watchlist_stocks` — 新增 10 列(price, entry_low/high, stop_loss, currency, source 等)
**写入保护**:所有 `write_*` 函数校验币种,写入 USD 直接拒绝。
**所有高危写入者已迁移到 DB**
- `price_monitor.py` — holdings + portfolio_summary + watchlist
- `strategy_lifecycle.py` — regenerate_all → holdings + strategies + watchlist + summary
- `holdings_reconciliation.py` — holdings + strategies + summary
- `process_trade.py` — holdings + strategies
- `import_holding_xls.py` — holdings + summary
- JSON 保留作为冷备(DB 写失败不影响 JSON 写入)
### 唯一价格源(消除多入口拉价)
**问题**17 个文件各自调用腾讯 `qt.gtimg.cn` 拉价,互不通信,币种转换不一致。
**修复**:所有价格读取改为 DB 优先,腾讯 API 仅作 fallback。
| 文件 | 改动 |
|------|------|
| `mofin_db.py` | 新增 `get_price_from_db()` / `get_prices_batch_from_db()` 通用工具 |
| `strategy_lifecycle.py` | `batch_fetch_prices()` + `get_price_tencent()` DB 优先 |
| `stale_push_wlin.py` | `fetch_trend_data()` + 移除硬编码 0.87 fallback |
| `per_stock_reassess.py` | 价格从 DB 读,不再自拉腾讯 |
| `stale_detector.py` | `fetch_prices()` DB 优先 |
| `server.py` | `/api/portfolio` DB 优先 |
| `strategy_evaluator.py` | `fetch_prices()` DB 优先 |
| `technical_analysis.py` | `get_quote()` DB 优先,移除 60s 缓存 |
| `stock_profile.py` | `get_quote()` DB 优先 |
| `collect_evaluation_data.py` | `fetch_tencent_data()` DB 优先 |
| `branch_scanner.py` (×2) | `get_price()` DB 优先 |
| `strategy_review.py` | `fetch_price()` DB 优先 |
| `xiaoguo_signal_consumer.py` | `fetch_quote()` DB 优先 |
### price_monitor 保活
- **cron**:交易日 9:00-16:00 每 2 分钟 `price_monitor.py`
- **健康检查**:每 10 分钟检查进程 + DB 新鲜度
- **健康检查脚本**`scripts/check_price_monitor.py`
### NEAR_SL 误报修复
- `stale_detector.py`:距止损 <5% 时加浮盈判断
- 浮盈 >5% → `[PROFIT_PROTECT]`(利润保护,不报警)
- 浮盈 ≤5% → `[NEAR_SL]`(真正危险)
### 小果连接统一
- 全部改为 `node122`(机器名),`/etc/hosts` 自动解析 LAN/EasyTier
- 涉及 5 个文件:market_screener, xiaoguo_scanner, xiaoguo_news_processor, intraday_health_check, ocr_client
### 待办(知微)
- [ ] 明天开盘验证 price_monitor 正常更新 DB
- [ ] 验证 `[PROFIT_PROTECT]` 标记取代 `[NEAR_SL]` 误报
- [ ] 如果启用 AlphaSift`ALPHASIFT_ENABLED=true python3 mo_alphasift_bridge.py`
---
## 2026-07-01 (续) — 统一读取层 + 现金日志
### mo_data.py — 统一数据读取层
替代所有 `json.load(open(portfolio.json))` 等直接读 JSON 的方式。
```
mo_data.read_portfolio() → 返回 portfolio.json 等价 dict(数据来自 DB
mo_data.read_decisions() → 返回 decisions.json 等价 dict
mo_data.read_watchlist() → 返回 watchlist.json 等价 dict
```
- DB 优先,JSON 冷备(DB 不可用时自动 fallback
- 返回结构完全兼容旧代码,无需改调用方
- 16 个文件已通过批量替换迁移
### cash_log 表 — 现金变更追踪
新表 `cash_log`,记录每次现金变动:
| 字段 | 说明 |
|------|------|
| `cash_before/after` | 变更前后可用现金 |
| `frozen_before/after` | 变更前后冻结资金 |
| `change_amount` | 变动额(正=入金/卖股,负=出金/买股) |
| `source` | 来源:screenshot / manual / import_xls / trade |
| `note` | 备注 |
| `verified` | 是否经 Dad 确认 |
写入:`write_cash_log(conn, data)`
查询:`query_cash_log(conn, limit=20)`
### 待办(知微)
- [ ] 明天开盘验证 price_monitor 正常更新 DB
- [ ] 验证 `[PROFIT_PROTECT]` 标记取代 `[NEAR_SL]` 误报
- [ ] cash_log 目前只是建表,需要在截图导入/手动改现金时调用 `write_cash_log` 记录变更
- [ ] 如果启用 AlphaSift`ALPHASIFT_ENABLED=true python3 mo_alphasift_bridge.py`
---
## 2026-07-02 — 筹码因子模块上线(知微)
> 基于中信建投《筹码分布因子系统构建》研报
### 新增文件
| 文件 | 用途 |
|------|------|
| `scripts/chip_factors.py` | 筹码因子计算引擎 — 分钟K线+筹码分布+情景权重 |
| `data/chip_cache/*.json` | 33只持仓/自选股的每日筹码状态缓存 |
### 修改文件
| 文件 | 变更 |
|------|------|
| `mo_provider.py` | 新增 `get_minute_kline()` — 东方财富push2分钟K线(1s限流,单次≤240条) |
| `strategy_lifecycle.py` | 新增 `calc_chip_sr()` — 筹码支撑/阻力计算 + `reassess_strategy` 集成共振检测 |
### 筹码因子模块详情
**`scripts/chip_factors.py`** (262行):
- `_build_chip_distribution()` — 从60日日线OHLCV估算筹码分布,每日衰减0.97
- `calc_all()` — 计算三大因子:筹码穿透率(PTR)、当日穿透率(ptr_today)、筹码乖离率(bias)
- `batch_calc()` — 批量计算全部持仓+自选(1.5s限流)
- `chip_cache/` — 缓存每日筹码状态,支持因子滚动计算
**`strategy_lifecycle.py` 集成**:
- `calc_chip_sr()` — 从筹码分布找出强支撑/阻力(2%区间聚合)
- `detect_scenario()` 情景判定 → 动态权重:震荡市0.9 > 轮动市0.6 > 上涨0.4 > 急跌0.2
- 共振检测 ⚡:筹码支撑 vs 枢轴弱支撑差距<3%时标记共振
- 权重<0.5时标记不可靠,止损/止盈仍以枢轴为主
### 首次运行结果
- 33只股票完成筹码分布计算
- 最高亏损筹码占比:万科99.5% / 神华98.6% / 比亚迪股份98.7%
- 最低亏损筹码占比:建滔4.0% / 药明康德2.1%
### 注意
- 代码在 master 已推送,mohe 侧无需额外操作
- 下次开盘后 strategy_lifecycle 会自动加载筹码 S/R