# MoFin / TDX-Relay 协作文档

> 最后更新：2026-06-12
> 维护人：知微 + 小小莫(xxm)
> 铁律：任何 relay 相关改动必须先读本文档，改完必须同步更新

---

## 一、什么是 tdx-relay

tdx-relay 是小小莫（xxm）开发的 Windows 端通达信中继程序。
作用：通过 opentdx 协议直连招商证券 7727 扩展行情服务器，
为 MoFin 系统提供港股低延迟实时行情。

### 为什么需要它

原本 MoFin 的港股行情来源是腾讯 API（qt.gtimg.cn），
存在约 15 分钟延迟，对于盘中决策不够及时。
tdx-relay 将港股行情延迟从约 15 分钟降到接近实时（1~3 秒）。

---

## 二、系统架构

```
Windows 端（小小莫负责）
┌─────────────────────────────────────────┐
│  tdx-relay 项目                          │
│                                          │
│  tdx_client.py                           │
│  └─ opentdx MacExtendedClient            │
│     └─ 直连 招商证券 7727 扩展行情服务器  │
│         → 拉取 17 只港股实时行情          │
│                                          │
│  run_relay.py                            │
│  └─ 断线自动重连(5s/15s/30s 三次退避)    │
│  └─ 推送 → POST /api/update/realtime     │
│                                          │
│  start_tdx_relay.bat                     │
│  └─ 一键启动脚本                         │
└───────────────┬─────────────────────────┘
                │ HTTP POST (JSON)
                ▼
Linux 端（知微负责）
┌─────────────────────────────────────────┐
│  MoFin 系统 (web-dashboard)              │
│                                          │
│  server.py                               │
│  ├─ /api/update/realtime (POST)          │
│  │   ← 接收 tdx-relay 推送的实时行情     │
│  │   → 更新 portfolio.json + watchlist   │
│  │   → 写入 data_source = "tdx_relay"    │
│  │                                        │
│  ├─ /api/relay/status (GET)              │
│  │   ← 查询 relay 状态（在线/离线/时间） │
│  │                                        │
│  price_monitor.py                        │
│  └─ relay_active 检测                    │
│     ├─ relay 在线 → 跳过港股腾讯API拉取  │
│     │   （保留 tdx-relay 的实时价不覆盖） │
│     └─ relay 掉线 → 回退腾讯 API 兜底    │
│                                          │
│  数据文件                                │
│  ├─ data/portfolio.json                  │
│  │   └─ 每只港股: data_source=txton/tdx  │
│  ├─ data/watchlist.json                  │
│  └─ data/relay_state.json (新增)         │
│      └─ online: true/false               │
│      └─ last_ping: 时间戳                │
└─────────────────────────────────────────┘
```

## 三、职责边界

### 小小莫（xxm）— Windows 端

负责：
1. tdx_client.py 的开发维护
   - 直连券商行情服务器的稳定性
   - 港股代码列表的维护（当前 17 只）
   - 行情数据的正确性验证
2. run_relay.py 的重连机制
   - 断线自动恢复（3 次退避重连）
   - relan 状态上报
3. 行情推送的稳定性
   - 每 X 秒推送一次实时行情
   - 推送失败的处理
4. Windows 端部署维护
   - 开机自启动
   - 日志管理
   - 异常告警

不负责：
- MoFin API 的修改（但需要配合 server.py 新增端点）
- Linux 端 price_monitor 的回退逻辑
- 持仓分析和策略制定

### 知微（zhiwei）— Linux 端（MoFin）

负责：
1. MoFin API 的 relay 兼容
   - /api/update/realtime 端点（已实现）
   - /api/relay/status 端点（待实现）
   - relay_state 持久化（待实现）
2. price_monitor 的 relay 检测（待实现）
   - relay 在线 → 跳过港股腾讯 API 拉取
   - relay 掉线 → 回退腾讯 API 兜底
3. tdx-relay 接入后的数据一致性保障
   - 腾讯 API 和 tdx-relay 的数据源标记区分
   - 价格更新不互相覆盖
4. 行情来源对分析层的透明化
   - 分析层（cron prompt）不需要关心行情来源
   - 直接读 portfolio.json 即可
   - 数据源标记在 data_source 字段中

不负责：
- Windows 端程序的开发和部署
- 通达信协议的细节
- 券商行情服务器的维护

### 共同维护

1. 港股代码列表 — 两边保持一致
2. 数据格式 — tdx-relay 推送的 JSON 格式与 MoFin 期望的格式
3. 接口联调 — 新端点上线后的验证

---

## 四、数据流详解

### 正常流程（relay 在线）

```
tdx-relay (Windows)
  │ 每 X 秒推送 {stocks: [{code, price, change_pct, ...}]}
  │ POST → http://192.168.1.246:8899/api/update/realtime
  ▼
server.py 接收
  ├─ 更新 portfolio.json（港股 data_source = "tdx_relay"）
  ├─ 更新 watchlist.json（港股 data_source = "tdx_relay"）
  └─ 更新 relay_state.json（online=true, last_ping=now）
      │
      ▼
  price_monitor.py（每分钟运行）
    ├─ A股 → 腾讯 API（不变）
    ├─ 港股 → 检查 relay_state
    │   ├─ relay 在线 → 跳过（保留 tdx-relay 的实时价）
    │   └─ relay 离线（>60秒无推送）→ 回退腾讯 API
    └─ 数据源标记 → 写入 portfolio/watchlist
```

### 异常流程（relay 离线）

```
tdx-relay 断线
  │ 60秒内无推送
  ▼
price_monitor.py 检测到 relay_state.online=false
  │ 或 last_ping > 60秒前
  ├─ 港股 → 回退腾讯 API 拉取
  ├─ 写入时 data_source = "tencent"
  └─ 记录日志 "relay offline, fallback to tencent"

tdx-relay 恢复
  │ 推送到达 /api/update/realtime
  ▼
server.py 接收更新
  ├─ 更新 relay_state.json（online=true）
  └─ 正常接收行情
```

---

## 五、接口规范

### POST /api/update/realtime （已实现）

接收 tdx-relay 推送的实时行情。

请求格式：
```json
{
  "stocks": [
    {
      "code": "00700",
      "price": 467.20,
      "change_pct": 3.09,
      "high": 470.00,
      "low": 460.00,
      "open": 462.00,
      "volume": 15000000
    }
  ],
  "source": "tdx_relay"
}
```

响应：
```json
{
  "status": "ok",
  "updated": 15,
  "source": "tdx_relay",
  "timestamp": "2026-06-12T14:30:00"
}
```

### GET /api/relay/status （待实现）

查询 tdx-relay 当前状态。

响应：
```json
{
  "online": true,
  "source": "tdx_relay",
  "last_ping": "2026-06-12T14:29:55",
  "age_seconds": 5,
  "stocks_count": 15,
  "fallback_active": false
}
```

---

## 六、当前实现状态

### 已完成（全部 ✅）
- server.py `/api/update/realtime` 端点 ✅
- server.py `/api/relay/status` GET 端点 ✅
- relay_state.json 持久化 ✅
- price_monitor.py relay_active 检测 ✅
- price_monitor 回退逻辑（relay 离线→腾讯 API 兜底）✅
- tdx-relay 心跳上报（每15秒推送）✅
- 断线自动重连（3次退避）✅
- 17只港股全量推送 ✅
- 数据层重构：JSON+SQLite 双写 + 消费者切 SQLite 优先 ✅

### 2026-06-20 数据层重构（小小莫完成）

**新增文件**：
- `mofin_db.py` — 统一 SQLite 访问层（13张表 + 18个查询函数 + 4个写入函数）
- `migrate_all.py` — 一次性 JSON→SQLite 迁移脚本
- `mofin_query.py` — 通用查询工具
- `docs/DATABASE_ARCHITECTURE.md` — 完整架构文档

**修改文件**：
- `market_watch.py` — JSON+SQLite 双写
- `multi_timeframe.py` — K线双写
- `price_monitor.py` — 价格事件双写
- `server.py` — SQLite 优先读取（/api/portfolio, /api/watchlist, /api/overview, /api/market）
- `strategy_lifecycle.py` — SQLite 优先读取（stock_sector_map, market_context, holdings, watchlist）
- `market_insight.py` — SQLite 优先读取
- `strategy_feedback.py` — SQLite 优先读取 price_events
- `system_health_check.py` — SQLite 优先读取 price_events

**设计原则**：
- 所有消费者：SQLite 优先 → 失败回退 JSON，系统不中断
- 所有写入：JSON+SQLite 双写，SQLite 失败不影响 JSON 管道
- 迁移脚本幂等可重跑，JSON 文件不修改

---

## 七、港股代码列表（双方保持一致）

当前 17 只港股（来自 portfolio.json + watchlist.json）：

| 代码 | 名称 | 持仓/自选 |
|------|------|----------|
| 00700 | 腾讯控股 | 持仓 |
| 00981 | 中芯国际 | 持仓 |
| 01211 | 比亚迪股份 | 持仓 |
| 09988 | 阿里巴巴 | 持仓 |
| 02202 | 万科企业 | 持仓 |
| 02388 | 中银香港 | 持仓 |
| 01478 | 丘钛科技 | 持仓 |
| 09868 | 小鹏集团 | 自选(已清仓) |
| 01088 | 中国神华 | 持仓 |
| 02359 | 药明康德 | 自选 |
| 01888 | 建滔积层板 | 自选 |
| 00968 | 信义光能 | 自选 |
| 01070 | TCL电子 | 自选 |
| 02318 | 中国平安 | 自选 |
| 02628 | 中国人寿 | 自选 |
| 06160 | 百济神州 | 自选(已清仓) |
| 06869 | 长飞光纤 | 自选 |

---

## 八、故障处理

| 现象 | 可能原因 | 处理方式 |
|------|---------|---------|
| relay 显示离线 | Windows 端掉线 | 检查 Windows 端运行状态，双击 start_tdx_relay.bat |
| relay 在线但数据不更新 | 推送异常 | 查 Windows 端日志，重启 tdx-relay |
| 港股价格异常 | 数据源错乱 | 检查 data_source 字段，确认 relay 是否覆盖了错误数据 |
| 港股价格用腾讯旧数据 | relay 离线超过 60s 自动回退 | 正常行为，relay 恢复后自动切回 |
