# 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 个 Fetcher,TDX 优先、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.cn(15分钟延迟兜底) DSA 数据源 → mo_provider(16 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 正常