docs: update CHANGELOG + data model + mark decisions migration complete
This commit is contained in:
+65
-291
@@ -1,318 +1,92 @@
|
||||
# MoFin 架构改革 — 变更日志
|
||||
|
||||
> 日期:2026-06-29 ~ 2026-06-30
|
||||
> 执行:Sisyphus (小小莫)
|
||||
> 背景:total_assets 频繁计算错误(遗漏 frozen_cash)、币种混淆(CNY/HKD)、港股 15 分钟延迟
|
||||
> 日期:2026-06-29 ~ 2026-07-03
|
||||
> 执行:Sisyphus (小小莫) + Zhiwei (知微)
|
||||
|
||||
---
|
||||
|
||||
## 新增文件
|
||||
## 2026-07-03 — JSON 彻底移除 + 币种架构修正
|
||||
|
||||
| 文件 | 用途 |
|
||||
|------|------|
|
||||
| `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` | 数据新鲜度校验(知微创建) |
|
||||
### JSON→DB 全面迁移 (32+ 文件)
|
||||
|
||||
## 修改文件
|
||||
**数据层**
|
||||
- `mo_data.py`:删除所有 JSON fallback,纯 SQLite 读取
|
||||
- `mofin_db.py`:
|
||||
- `write_holding_strategy` 改为 DELETE+INSERT(旧 ON CONFLICT 静默失败)
|
||||
- `holding_strategies` 新增 10 列:avg_price, decision_timestamp, note, quality_check, quality_checked_at, quality_issues_json, position_advice, signal_factors_json, time_horizon, decision_type
|
||||
- 新增 `live_prices` / `mtf_cache` / `capital_flow_cache` 三张表 + 读写函数
|
||||
- 已有 `market_snapshots` 表接替 market.json
|
||||
|
||||
| 文件 | 变更 |
|
||||
|------|------|
|
||||
| `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 集成 |
|
||||
**server.py**
|
||||
- 新增 `_save_portfolio` / `_save_decision` / `_save_watchlist` 写函数
|
||||
- 所有 13 个 API 写端点切到 DB,读端点删除 JSON fallback
|
||||
|
||||
## 服务器部署
|
||||
**脚本层**
|
||||
- 15 个文件 `json.load → mo_data.read_*()`
|
||||
- 12 个文件 `json.dump → mofin_db.write_*()` 或直接删除
|
||||
- strategy_lifecycle JSON 冷备行全部删除
|
||||
- branch_scanner / prune_branches 切到 DB
|
||||
- system_audit / stale_push_wlin / refresh_mtf_cache JSON→DB
|
||||
|
||||
| 操作 | 状态 |
|
||||
|------|------|
|
||||
| `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) | ✅ |
|
||||
**LLM Prompt**
|
||||
- evaluation-daily v2:`evaluation.json` → DB 表
|
||||
- knowledge-extraction v1:`decisions.json` → DB 表
|
||||
- analytics.py:删除 JSON 路径常量
|
||||
|
||||
### DSA Web 访问
|
||||
**已移除的 JSON 文件**(不再被任何代码读写)
|
||||
- portfolio.json / decisions.json / watchlist.json
|
||||
- live_prices.json / multi_tf_cache.json / market.json / capital_flow_cache.json
|
||||
|
||||
- **地址**:`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 文档界面。 |
|
||||
**港股** — 个股 price/cost/stop_loss 存 **HKD**,`currency='HKD'`
|
||||
**A股** — 个股 price/cost/stop_loss 存 **CNY**,`currency='CNY'`
|
||||
**总资产** — `calc_total_assets()` 汇总时港股 HKD×汇率→CNY
|
||||
|
||||
## 架构变化总结
|
||||
| 场景 | 港股 | A股 |
|
||||
|------|------|-----|
|
||||
| 个股显示(股软对照) | HKD | CNY |
|
||||
| 技术位(止损/止盈/买入区) | HKD | CNY |
|
||||
| 总资产 / 总市值 / P&L | CNY(汇总时转换) | CNY |
|
||||
|
||||
### 关键修复
|
||||
|
||||
- 根 `price_monitor.py` 与 `scripts/price_monitor.py` 不一致(前者存 HKD,后者转 CNY)→ 统一:存 HKD,不转换
|
||||
- `s.get('price', 0)` 在 price 为 None 时返回 None 导致 TypeError → 改为 `s.get('price') or 0`
|
||||
- 东财 API 限流(之前 0.1s 间隔疯狂刷被封)→ 第一只失败立刻切腾讯兜底
|
||||
|
||||
### 验证
|
||||
|
||||
**之前**:
|
||||
```
|
||||
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+ 个文件中各自硬编码
|
||||
holdings: 19 (8 HKD + 11 CNY)
|
||||
decisions: 19 (8 HKD + 11 CNY)
|
||||
total_assets: stored = calculated ✅
|
||||
```
|
||||
|
||||
**之后**:
|
||||
```
|
||||
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
|
||||
## 2026-07-01 — 统一读取层 + 现金日志
|
||||
|
||||
### DSA Web 界面上线
|
||||
### 新增
|
||||
- `mo_data.py` — `read_portfolio()` / `read_decisions()` / `read_watchlist()`
|
||||
- `mofin_db.py` — `cash_log` 表 + `write_cash_log` / `query_cash_log`
|
||||
|
||||
- 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 正常
|
||||
### 修改
|
||||
- 16 个文件 `json.load → mo_data.read_*()`
|
||||
- HK 股成本 HKD→CNY 修复(import_holding_xls 导入时转换)
|
||||
|
||||
---
|
||||
|
||||
## 2026-07-01 — DB 迁移 + 唯一价格源 + 保活机制
|
||||
## 2026-06-30 — 初始架构重构
|
||||
|
||||
### JSON → DB 完整迁移(币种约束)
|
||||
### 新增
|
||||
- `mo_models.py` — `calc_total_assets()`, `is_hk_stock()`, `get_hk_rate()`, `to_cny()`, `validate_portfolio()`
|
||||
- `mo_config.py` — 配置单例
|
||||
- `mo_bridge.py` — DSA 集成桥
|
||||
- `mo_provider.py` — DSA 数据源适配器
|
||||
- `scripts/data_validate.py`, `holdings_reconciliation.py`, `process_trade.py`(知微)
|
||||
- DSA Web UI: `http://192.168.1.246:8001`
|
||||
|
||||
**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
|
||||
### 修改
|
||||
- `price_monitor.py`:港股腾讯→东方财富 + 统一 total_assets
|
||||
- 8 个文件散落 `is_hk_stock` / `total_assets` 统一到 mo_models
|
||||
|
||||
+162
-159
@@ -1,159 +1,162 @@
|
||||
# decisions.json → SQLite 数据库迁移需求
|
||||
|
||||
## 背景
|
||||
|
||||
当前系统所有策略数据存在 `/home/hmo/web-dashboard/data/decisions.json`,一个约 50~60 条策略的 JSON 文件。
|
||||
|
||||
## 现状痛点
|
||||
|
||||
| 问题 | 举例 |
|
||||
|------|------|
|
||||
| 没有写入锁,并发写会损坏 | price_monitor + per_stock_reassess 同时写,JSON 截断 |
|
||||
| 币种字段不统一 | 港股 price 曾经存 HKD 也存过 CNY,修了几轮才用 currency 标记 |
|
||||
| 缺乏 schema 校验 | 空字段、类型错误(str 写成了 int)无声失败 |
|
||||
| 无 changelog 审计 | 谁在什么时候改了哪个字段,查不了 |
|
||||
| 没有事务回滚 | 写一半 crash,整个文件废了 |
|
||||
| 只能全量读 | 50 条策略每次全部加载,浪费 token |
|
||||
| 各脚本自拉价格 | stale_detector 拉一次腾讯 API,per_stock_reassess 又拉一次 |
|
||||
|
||||
## 需求目标
|
||||
|
||||
**单线程写入 / 多线程安全读**。
|
||||
将 decisions.json 迁移到 `mofin.db`(已有该数据库),建 `strategies` 表。
|
||||
|
||||
## 表结构
|
||||
|
||||
```sql
|
||||
CREATE TABLE strategies (
|
||||
code TEXT PRIMARY KEY, -- 股票代码,如 "00700"
|
||||
name TEXT NOT NULL, -- 股票名称
|
||||
type TEXT DEFAULT '自选策略', -- 持仓策略 / 自选策略
|
||||
status TEXT DEFAULT 'active', -- active / updated / stale
|
||||
currency TEXT DEFAULT 'CNY', -- CNY / HKD。港股固定 HKD
|
||||
|
||||
-- 价格与仓位
|
||||
price REAL, -- 最新价格(原始币种,港股=HKD,A股=CNY)
|
||||
price_cny REAL, -- 折算为人民币的价格(统一口径用)
|
||||
cost REAL, -- 持仓成本(有持仓时)
|
||||
shares INTEGER, -- 持仓股数
|
||||
share INTEGER, -- 同 shares,历史遗留字段
|
||||
|
||||
-- 策略参数
|
||||
entry_low REAL, -- 买入区间下沿(原始币种)
|
||||
entry_high REAL, -- 买入区间上沿(原始币种)
|
||||
stop_loss REAL, -- 止损价
|
||||
take_profit REAL, -- 止盈/目标价
|
||||
stop_loss_cny REAL, -- 止损(人民币,统一口径用)
|
||||
take_profit_cny REAL, -- 止盈(人民币)
|
||||
rr_ratio REAL, -- 盈亏比
|
||||
timing_signal TEXT, -- 短词信号:买入/加仓/持有/观望/冷却中
|
||||
|
||||
-- 来源与状态
|
||||
trigger_reason TEXT, -- 策略生成原由
|
||||
created_at TEXT, -- ISO时间
|
||||
updated_at TEXT, -- 最后更新时间
|
||||
reassessed_at TEXT, -- 最近一次重评时间
|
||||
action TEXT, -- 最新操作摘要文本
|
||||
|
||||
-- JSON 嵌套字段(存为 TEXT,应用层 JSON parse)
|
||||
analysis TEXT, -- JSON: 分析详情
|
||||
trigger TEXT, -- JSON: 触发条件
|
||||
changelog TEXT, -- JSON: 变更历史数组
|
||||
signal_factors TEXT, -- JSON: 因子列表
|
||||
tech_snapshot TEXT, -- JSON: 技术面快照
|
||||
action_note TEXT, -- 长文本动作说明
|
||||
sector_context TEXT -- 行业上下文
|
||||
);
|
||||
```
|
||||
|
||||
### 为什么不全部展开成列
|
||||
|
||||
analysis 和 trigger 有嵌套结构且未来可能加字段。存 JSON 字符串,应用层 parse。查询止损/止盈用 `json_extract()`。
|
||||
|
||||
## 读写接口需求
|
||||
|
||||
### 写操作(高频,每 2 分钟)
|
||||
|
||||
price_monitor 每轮更新所有持仓 + 自选的价格:
|
||||
|
||||
```sql
|
||||
INSERT INTO strategies (code, price, price_cny, currency, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT(code) DO UPDATE SET
|
||||
price = excluded.price,
|
||||
price_cny = excluded.price_cny,
|
||||
updated_at = excluded.updated_at;
|
||||
```
|
||||
|
||||
价格更新不涉及其他字段。港股:price=HKD,price_cny=HKD×汇率。
|
||||
A股:price=price_cny。
|
||||
|
||||
### 写操作(低频,策略重评时)
|
||||
|
||||
per_stock_reassess 跑完单股重评后更新全部策略参数:
|
||||
|
||||
```sql
|
||||
UPDATE strategies SET
|
||||
entry_low = ?, entry_high = ?, stop_loss = ?,
|
||||
take_profit = ?, rr_ratio = ?, timing_signal = ?,
|
||||
stop_loss_cny = ?, take_profit_cny = ?,
|
||||
currency = ?,
|
||||
analysis = ?,
|
||||
trigger = ?,
|
||||
reassessed_at = ?,
|
||||
changelog = json_insert(changelog, '$[#]', ?)
|
||||
WHERE code = ?;
|
||||
```
|
||||
|
||||
### 读操作(各报告脚本)
|
||||
|
||||
所有 LLM cron、no_agent 脚本统一从 `strategies` 表读,不再拉腾讯 API:
|
||||
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE status = 'active' ORDER BY code;
|
||||
```
|
||||
|
||||
按币种过滤:
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE currency = 'HKD';
|
||||
```
|
||||
|
||||
读某只具体股票:
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE code = '00700';
|
||||
```
|
||||
|
||||
## 不变的输出
|
||||
|
||||
1. **保留 decisions.json 同步输出**(过渡期 2 周)。每次写 DB 后,同步写一份 decisions.json 给旧脚本兼容。
|
||||
2. **输出格式不做大改**。JSON decode analysis/trigger 后保持现有字段名。
|
||||
|
||||
## 不允许的行为
|
||||
|
||||
1. ❌ 各脚本自行拉腾讯 API 获取价格。价格入口只有 price_monitor。
|
||||
2. ❌ 直接写 decisions.json。全部走 DB。
|
||||
3. ❌ 变更 decisions.json 的输出字段名/格式(过渡期兼容)。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. `strategies` 表有数据,decisions.json 和 `SELECT * FROM strategies` 内容一致
|
||||
2. price_monitor 跑一轮后 DB 里的 price 更新正确(港股 HKD,A 股 CNY)
|
||||
3. per_stock_reassess 跑完单股后 DB 里对应股票策略更新
|
||||
4. stale_detector 从 DB 读数据,输出和从 JSON 读一样
|
||||
5. 并发读写(price_monitor 2min + stale_detector 同时跑)不损坏数据
|
||||
6. 迁移后旧 decisions.json 仍同步更新
|
||||
|
||||
## 相关文件路径
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `/home/hmo/MoFin/price_monitor.py` | 价格监控,每2分钟写price |
|
||||
| `/home/hmo/MoFin/scripts/strategy_lifecycle.py` | 策略生命周期,reassess_strategy() |
|
||||
| `/home/hmo/MoFin/scripts/per_stock_reassess.py` | 单股重评入口 |
|
||||
| `/home/hmo/MoFin/scripts/stale_push_wlin.py` | 自选买入提醒 |
|
||||
| `/home/hmo/web-dashboard/data/decisions.json` | 当前JSON文件 |
|
||||
| `/home/hmo/MoFin/data/mofin.db` | 目标数据库(已有market/trend等表) |
|
||||
|
||||
## 联系人
|
||||
|
||||
有问题问 hmo(老爸)。笑笑负责代码实现,测试完成后通知老爸验收。
|
||||
# decisions.json → SQLite 数据库迁移需求
|
||||
|
||||
> **✅ 已完成 (2026-07-03)** — 全部迁移到 `holding_strategies` 表。
|
||||
> decisions.json 不再被任何代码读写。详见 CHANGELOG.md。
|
||||
|
||||
## 背景
|
||||
|
||||
当前系统所有策略数据存在 `/home/hmo/web-dashboard/data/decisions.json`,一个约 50~60 条策略的 JSON 文件。
|
||||
|
||||
## 现状痛点
|
||||
|
||||
| 问题 | 举例 |
|
||||
|------|------|
|
||||
| 没有写入锁,并发写会损坏 | price_monitor + per_stock_reassess 同时写,JSON 截断 |
|
||||
| 币种字段不统一 | 港股 price 曾经存 HKD 也存过 CNY,修了几轮才用 currency 标记 |
|
||||
| 缺乏 schema 校验 | 空字段、类型错误(str 写成了 int)无声失败 |
|
||||
| 无 changelog 审计 | 谁在什么时候改了哪个字段,查不了 |
|
||||
| 没有事务回滚 | 写一半 crash,整个文件废了 |
|
||||
| 只能全量读 | 50 条策略每次全部加载,浪费 token |
|
||||
| 各脚本自拉价格 | stale_detector 拉一次腾讯 API,per_stock_reassess 又拉一次 |
|
||||
|
||||
## 需求目标
|
||||
|
||||
**单线程写入 / 多线程安全读**。
|
||||
将 decisions.json 迁移到 `mofin.db`(已有该数据库),建 `strategies` 表。
|
||||
|
||||
## 表结构
|
||||
|
||||
```sql
|
||||
CREATE TABLE strategies (
|
||||
code TEXT PRIMARY KEY, -- 股票代码,如 "00700"
|
||||
name TEXT NOT NULL, -- 股票名称
|
||||
type TEXT DEFAULT '自选策略', -- 持仓策略 / 自选策略
|
||||
status TEXT DEFAULT 'active', -- active / updated / stale
|
||||
currency TEXT DEFAULT 'CNY', -- CNY / HKD。港股固定 HKD
|
||||
|
||||
-- 价格与仓位
|
||||
price REAL, -- 最新价格(原始币种,港股=HKD,A股=CNY)
|
||||
price_cny REAL, -- 折算为人民币的价格(统一口径用)
|
||||
cost REAL, -- 持仓成本(有持仓时)
|
||||
shares INTEGER, -- 持仓股数
|
||||
share INTEGER, -- 同 shares,历史遗留字段
|
||||
|
||||
-- 策略参数
|
||||
entry_low REAL, -- 买入区间下沿(原始币种)
|
||||
entry_high REAL, -- 买入区间上沿(原始币种)
|
||||
stop_loss REAL, -- 止损价
|
||||
take_profit REAL, -- 止盈/目标价
|
||||
stop_loss_cny REAL, -- 止损(人民币,统一口径用)
|
||||
take_profit_cny REAL, -- 止盈(人民币)
|
||||
rr_ratio REAL, -- 盈亏比
|
||||
timing_signal TEXT, -- 短词信号:买入/加仓/持有/观望/冷却中
|
||||
|
||||
-- 来源与状态
|
||||
trigger_reason TEXT, -- 策略生成原由
|
||||
created_at TEXT, -- ISO时间
|
||||
updated_at TEXT, -- 最后更新时间
|
||||
reassessed_at TEXT, -- 最近一次重评时间
|
||||
action TEXT, -- 最新操作摘要文本
|
||||
|
||||
-- JSON 嵌套字段(存为 TEXT,应用层 JSON parse)
|
||||
analysis TEXT, -- JSON: 分析详情
|
||||
trigger TEXT, -- JSON: 触发条件
|
||||
changelog TEXT, -- JSON: 变更历史数组
|
||||
signal_factors TEXT, -- JSON: 因子列表
|
||||
tech_snapshot TEXT, -- JSON: 技术面快照
|
||||
action_note TEXT, -- 长文本动作说明
|
||||
sector_context TEXT -- 行业上下文
|
||||
);
|
||||
```
|
||||
|
||||
### 为什么不全部展开成列
|
||||
|
||||
analysis 和 trigger 有嵌套结构且未来可能加字段。存 JSON 字符串,应用层 parse。查询止损/止盈用 `json_extract()`。
|
||||
|
||||
## 读写接口需求
|
||||
|
||||
### 写操作(高频,每 2 分钟)
|
||||
|
||||
price_monitor 每轮更新所有持仓 + 自选的价格:
|
||||
|
||||
```sql
|
||||
INSERT INTO strategies (code, price, price_cny, currency, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT(code) DO UPDATE SET
|
||||
price = excluded.price,
|
||||
price_cny = excluded.price_cny,
|
||||
updated_at = excluded.updated_at;
|
||||
```
|
||||
|
||||
价格更新不涉及其他字段。港股:price=HKD,price_cny=HKD×汇率。
|
||||
A股:price=price_cny。
|
||||
|
||||
### 写操作(低频,策略重评时)
|
||||
|
||||
per_stock_reassess 跑完单股重评后更新全部策略参数:
|
||||
|
||||
```sql
|
||||
UPDATE strategies SET
|
||||
entry_low = ?, entry_high = ?, stop_loss = ?,
|
||||
take_profit = ?, rr_ratio = ?, timing_signal = ?,
|
||||
stop_loss_cny = ?, take_profit_cny = ?,
|
||||
currency = ?,
|
||||
analysis = ?,
|
||||
trigger = ?,
|
||||
reassessed_at = ?,
|
||||
changelog = json_insert(changelog, '$[#]', ?)
|
||||
WHERE code = ?;
|
||||
```
|
||||
|
||||
### 读操作(各报告脚本)
|
||||
|
||||
所有 LLM cron、no_agent 脚本统一从 `strategies` 表读,不再拉腾讯 API:
|
||||
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE status = 'active' ORDER BY code;
|
||||
```
|
||||
|
||||
按币种过滤:
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE currency = 'HKD';
|
||||
```
|
||||
|
||||
读某只具体股票:
|
||||
```sql
|
||||
SELECT * FROM strategies WHERE code = '00700';
|
||||
```
|
||||
|
||||
## 不变的输出
|
||||
|
||||
1. **保留 decisions.json 同步输出**(过渡期 2 周)。每次写 DB 后,同步写一份 decisions.json 给旧脚本兼容。
|
||||
2. **输出格式不做大改**。JSON decode analysis/trigger 后保持现有字段名。
|
||||
|
||||
## 不允许的行为
|
||||
|
||||
1. ❌ 各脚本自行拉腾讯 API 获取价格。价格入口只有 price_monitor。
|
||||
2. ❌ 直接写 decisions.json。全部走 DB。
|
||||
3. ❌ 变更 decisions.json 的输出字段名/格式(过渡期兼容)。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. `strategies` 表有数据,decisions.json 和 `SELECT * FROM strategies` 内容一致
|
||||
2. price_monitor 跑一轮后 DB 里的 price 更新正确(港股 HKD,A 股 CNY)
|
||||
3. per_stock_reassess 跑完单股后 DB 里对应股票策略更新
|
||||
4. stale_detector 从 DB 读数据,输出和从 JSON 读一样
|
||||
5. 并发读写(price_monitor 2min + stale_detector 同时跑)不损坏数据
|
||||
6. 迁移后旧 decisions.json 仍同步更新
|
||||
|
||||
## 相关文件路径
|
||||
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `/home/hmo/MoFin/price_monitor.py` | 价格监控,每2分钟写price |
|
||||
| `/home/hmo/MoFin/scripts/strategy_lifecycle.py` | 策略生命周期,reassess_strategy() |
|
||||
| `/home/hmo/MoFin/scripts/per_stock_reassess.py` | 单股重评入口 |
|
||||
| `/home/hmo/MoFin/scripts/stale_push_wlin.py` | 自选买入提醒 |
|
||||
| `/home/hmo/web-dashboard/data/decisions.json` | 当前JSON文件 |
|
||||
| `/home/hmo/MoFin/data/mofin.db` | 目标数据库(已有market/trend等表) |
|
||||
|
||||
## 联系人
|
||||
|
||||
有问题问 hmo(老爸)。笑笑负责代码实现,测试完成后通知老爸验收。
|
||||
|
||||
@@ -1,115 +1,114 @@
|
||||
# portfolio.json 数据模型
|
||||
# MoFin 数据模型
|
||||
|
||||
## 一句话
|
||||
> 数据已从 JSON 迁移到 SQLite。portfolio.json / decisions.json / watchlist.json 不再使用。
|
||||
|
||||
**总资产 = 持仓市值 + 可用现金 + 冻结资金**,三个数字必须全对,缺少任何一项数字就不对。
|
||||
## 核心表
|
||||
|
||||
## 字段说明
|
||||
| 表 | 对应旧 JSON | 用途 |
|
||||
|----|-----------|------|
|
||||
| `holdings` + `portfolio_summary` | portfolio.json | 持仓 + 汇总 |
|
||||
| `holding_strategies` | decisions.json | 策略/决策 |
|
||||
| `watchlist_stocks` | watchlist.json | 自选股 |
|
||||
| `live_prices` | live_prices.json | 实时价格快照 |
|
||||
| `mtf_cache` | multi_tf_cache.json | 多周期缓存 |
|
||||
| `market_snapshots` | market.json | 大盘数据 |
|
||||
| `capital_flow_cache` | capital_flow_cache.json | 资金流缓存 |
|
||||
| `cash_log` | 无 | 现金变更日志 |
|
||||
|
||||
```jsonc
|
||||
{
|
||||
// 持仓列表(price_monitor 每2分钟更新价格)
|
||||
"holdings": [
|
||||
{
|
||||
"code": "01888", // 股票代码
|
||||
"name": "建滔积层板", // 股票名称
|
||||
"shares": 500, // 持股数
|
||||
"price": 83.59, // 最新价(CNY!所有股票统一人民币计价)
|
||||
"cost": 88.23, // 成本价(CNY)
|
||||
"market_value": 41795.0 // 市值 = shares × price
|
||||
}
|
||||
// ...
|
||||
],
|
||||
## 总资产公式
|
||||
|
||||
// 现金(从 Dad 截图来源更新,price_monitor 不碰!)
|
||||
"cash": 92678.85, // 可用资金(人民币)
|
||||
"frozen_cash": 39481.40, // 冻结资金(T+2未交收/挂单占用)
|
||||
**总资产 = 持仓总市值(CNY) + 可用现金 + 冻结资金**
|
||||
|
||||
// 汇总(price_monitor 每2分钟自动重算)
|
||||
"total_mv": 835552.6, // 持仓市值 = Σ(shares × price)
|
||||
"total_assets": 967712.85, // 总资产 = total_mv + cash + frozen_cash
|
||||
"position_pct": 86.3, // 仓位% = total_mv / total_assets × 100
|
||||
|
||||
// 元数据
|
||||
"currency": "CNY", // 本文件所有价格均为人民币
|
||||
"updated_at": "2026-06-29 22:33:00", // 最近一次更新
|
||||
"source": "holding.xls / manual", // 持仓来源
|
||||
"data_model_version": "2" // 数据模型版本(防止新旧数据混淆)
|
||||
}
|
||||
```
|
||||
|
||||
## 现金流
|
||||
|
||||
### 现金如何被更新?
|
||||
|
||||
| 渠道 | 操作 | 更新字段 | 频次 |
|
||||
|------|------|---------|------|
|
||||
| holding.xls 导入 | `import_holding_xls.py` | cash, frozen_cash | Dad更新后 |
|
||||
| 成交截图 | 手动解析 + 对比旧数据计算变更 | cash(+/-), frozen_cash | Dad发送时 |
|
||||
| price_monitor | 只更新价格,不动现金 | 不更新 | 每2分钟 |
|
||||
| 手动修正 | Dad告知准确数字 | cash, frozen_cash | Dad告知时 |
|
||||
|
||||
### 现金变更追踪
|
||||
|
||||
portfolio.json 的 `cash_history` 数组记录了每次现金变更:
|
||||
```jsonc
|
||||
"cash_history": [
|
||||
{
|
||||
"time": "2026-06-29 22:23:47",
|
||||
"cash": 92678.85, // 更新后的可用资金
|
||||
"frozen": 39481.40, // 更新后的冻结资金
|
||||
"source": "manual:post-法拉电子-sell", // 变更来源
|
||||
"formula": "初始73758.85 + 法拉电子18920" // 计算过程
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 规则
|
||||
|
||||
1. **price_monitor 绝不能修改 cash / frozen_cash** — 它只更新 price 字段和 total_mv / total_assets
|
||||
2. 现金变更只能来自 Dad 截图、holding.xls 导入、或 Dad 手动告知
|
||||
3. 每次现金变更必须记录到 cash_history,注明来源和计算过程
|
||||
4. 所有报告脚本读总资产时,从 `portfolio.json.total_assets` 取,不要自己算
|
||||
`calc_total_assets()` (mo_models.py) 是唯一正确公式。
|
||||
|
||||
## 币种
|
||||
|
||||
- portfolio.json 全部存 CNY(港股价格 × HK_RATE 转人民币)
|
||||
- decisions.json 港股价格存 HKD 原值(带 `currency: "HKD"` 标记)
|
||||
- price_monitor 比较 decisions.json 中的价格和止损时:同币种(都是 HKD),直接比较
|
||||
- 报告输出港股价格时显示 HKD 并标注「(HKD)」
|
||||
### 个股层面
|
||||
|
||||
| 品种 | price | cost | currency | 说明 |
|
||||
|------|-------|------|----------|------|
|
||||
| 港股 | **HKD** | **HKD** | `HKD` | 跟股软显示一致,方便操作 |
|
||||
| A股 | **CNY** | **CNY** | `CNY` | |
|
||||
|
||||
技术位(stop_loss / take_profit / entry_low / entry_high)与 price 同币种。
|
||||
|
||||
### 汇总层面
|
||||
|
||||
`calc_total_mv()` / `calc_total_assets()` 汇总时自动将港股 HKD × `HK_RATE`(实时 API)转为 CNY。
|
||||
|
||||
```python
|
||||
# 个股 P&L:港股用 HKD 算,A股用 CNY 算
|
||||
profit_pct = (price - cost) / cost * 100 # 同币种,无需转换
|
||||
|
||||
# 总资产:港股市值自动转 CNY
|
||||
total_assets = calc_total_assets(pf) # 已处理 HKD→CNY
|
||||
```
|
||||
|
||||
### 禁止
|
||||
|
||||
- ❌ 港股 price(HKD) 和 A 股 price(CNY) 直接比较/相加
|
||||
- ❌ 港股 cost(HKD) 和 CNY price 混算 P&L
|
||||
- ❌ 硬编码汇率(`calc_total_mv` 内部调 `get_hk_rate()` 走实时 API)
|
||||
|
||||
## 数据流
|
||||
|
||||
```
|
||||
price_monitor (cron: */2 9-16)
|
||||
→ 东财/腾讯拉价格
|
||||
→ write_holdings_batch() → holdings 表 (price 更新)
|
||||
→ write_portfolio_summary() → portfolio_summary (total_mv/total_assets 重算)
|
||||
|
||||
regenerate_all (cron: 手动/定时)
|
||||
→ batch_fetch_prices() → 从 DB 读价格
|
||||
→ 技术分析 → 止损/止盈/买入区
|
||||
→ write_holding_strategy() → holding_strategies 表
|
||||
|
||||
server.py API
|
||||
→ 写端点: _save_portfolio / _save_decision / _save_watchlist → DB
|
||||
→ 读端点: mo_data.read_*() → DB
|
||||
```
|
||||
|
||||
## 现金
|
||||
|
||||
- `price_monitor` 只更新价格和汇总,不动现金
|
||||
- 现金变更通过截图导入 / holding.xls 导入 / 手动调整
|
||||
- `cash_log` 表记录每次变更(来源、before/after、备注)
|
||||
|
||||
## 常见错误
|
||||
|
||||
### ❌ total_assets 漏了冻结资金
|
||||
|
||||
### ❌ 港股价格转 CNY 再存
|
||||
```python
|
||||
# WRONG — 只加了可用现金,冻结资金漏了
|
||||
total_assets = market_value + cash
|
||||
# WRONG — 港股个股存 CNY 后股软对不上
|
||||
if is_hk_stock(code):
|
||||
price = price * HK_RATE
|
||||
|
||||
# RIGHT — 可用 + 冻结
|
||||
total_assets = market_value + cash + frozen_cash
|
||||
# RIGHT — 存 HKD 原值,汇总时由 calc_total_assets 转 CNY
|
||||
if is_hk_stock(code):
|
||||
currency = 'HKD'
|
||||
```
|
||||
|
||||
### ❌ 港股硬编码 ×0.866
|
||||
|
||||
### ❌ 混币计算
|
||||
```python
|
||||
# WRONG — 价格本身已经是 CNY(price_monitor在写入时就转了)
|
||||
mv = shares * price * 0.866
|
||||
# WRONG — price 是 HKD,cost 是 CNY,算出来没意义
|
||||
pnl = (price_hkd - cost_cny) / cost_cny
|
||||
|
||||
# RIGHT — price 已经是 CNY
|
||||
mv = shares * price
|
||||
# RIGHT — 同币种比较
|
||||
pnl = (price_hkd - cost_hkd) / cost_hkd
|
||||
```
|
||||
|
||||
### ❌ LLM 报告自己算总资产
|
||||
### ❌ 硬编码汇率
|
||||
```python
|
||||
# WRONG
|
||||
mv = shares * price * 0.87
|
||||
|
||||
```
|
||||
WRONG: 报告里写 "总资产 = 持仓市值 + 现金"
|
||||
RIGHT: 报告里写 "总资产 = portfolio.json.total_assets"
|
||||
# RIGHT — 用 calc_total_assets(内部调实时汇率)
|
||||
mv = calc_total_mv(holdings)
|
||||
```
|
||||
|
||||
## 版本记录
|
||||
## 版本
|
||||
|
||||
| 版本 | 日期 | 变更 |
|
||||
|------|------|------|
|
||||
| 1 | 2026-06-29以前 | 无规范,cash字段含义模糊 |
|
||||
| 2 | 2026-06-29 | 明确 cash=可用, frozen_cash=冻结, total_assets=市值+可用+冻结 |
|
||||
| 3 | 2026-07-03 | JSON→DB 迁移完成。港股个股存 HKD,汇总时转 CNY。 |
|
||||
| 2 | 2026-06-29 | 明确 cash/frozen_cash 字段含义 |
|
||||
| 1 | - | 无规范 |
|
||||
|
||||
Reference in New Issue
Block a user