trading-discipline-backend/docs/DATA_SOURCES.md
刘华勇 c19ca2aa4c feat: 初始化交易纪律系统后端
- 基于 axum + sqlx + tokio 的 Rust 后端服务
- 实现多数据源管理(东方财富/新浪/腾讯)含 failover 容错
- 数据源健康检查、请求日志记录与重放诊断
- 股票公司列表、历史K线、实时行情数据获取
- 配置 .gitignore:忽略 target 构建产物、.env 密钥、data 数据库
2026-06-17 15:46:48 +08:00

210 lines
5.5 KiB
Markdown
Raw 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.

# 📡 多数据源管理系统
支持多个金融数据源,自动降级、负载均衡、健康监控。
## 🏗️ 架构设计
```
┌─────────────────────┐
│ DataSourceManager │ ← 统一调度入口
│ (调度/降级/聚合) │
└──────────┬──────────┘
┌──────────┬───────────┼───────────┬──────────┐
▼ ▼ ▼ ▼ ▼
┌──────────┐┌─────────┐┌──────────┐┌─────────┐┌────────┐
│EastMoney ││ Sina ││ Tencent ││ Tushare ││ Mock │
│东方财富 ││新浪财经 ││腾讯财经 ││(需Token)││(测试用)│
│priority:1││ pri:2 ││ pri:3 ││ pri:1 ││ pri:99 │
└──────────┘└─────────┘└──────────┘└─────────┘└────────┘
│ │ │
▼ ▼ ▼
免费无需Token东方财富/新浪/腾讯)
```
## 🎯 运行模式
| 模式 | 说明 | 配置值 |
|------|------|--------|
| **Failover** (默认) | 按优先级依次尝试,失败自动降级到下一个源 | `failover` |
| **Aggregate** | 同时请求多个源,取最快返回结果 | `aggregate` |
| **PrimaryOnly** | 仅使用主源,失败不降级 | `primary_only` |
## 📊 数据源能力对比
| 数据源 | 公司列表 | 历史K线 | 实时行情 | 是否免费 | 限流 |
|--------|:------:|:------:|:------:|:------:|:----:|
| **东方财富** | ✅ | ✅ | ✅ | ✅ 免费 | 宽松 |
| **新浪财经** | ❌ | ✅ | ✅ | ✅ 免费 | 中等 |
| **腾讯财经** | ❌ | ✅ | ✅ | ✅ 免费 | 宽松 |
| **Tushare** | ✅ | ✅ | ✅ | 🔑 需Token | 严格 |
| **Mock** | ✅ | ✅ | ✅ | - | 无 |
## ⚙️ 配置说明
编辑 `backend/.env`
```env
# 运行模式
DATA_SOURCE_MODE=failover # failover | aggregate | primary_only
DATA_SOURCE_PRIMARY=eastmoney # 主数据源
DATA_SOURCE_TIMEOUT=15 # 超时秒数
# Tushare可选
TUSHARE_TOKEN=your_token_here
```
## 📡 管理 API
### 查看数据源状态
```bash
GET /api/datasources
```
响应示例:
```json
{
"code": 200,
"data": {
"mode": "failover",
"primary": "eastmoney",
"sources": [
{
"name": "eastmoney",
"type": "eastmoney",
"status": "healthy",
"priority": 1,
"success_rate": "100.0%",
"avg_latency_ms": 133
}
]
}
}
```
### 触发健康检查
```bash
POST /api/datasources/health
```
### 切换运行模式
```bash
PUT /api/datasources/mode
Content-Type: application/json
{ "mode": "aggregate" }
```
### 测试单个数据源
```bash
GET /api/datasources/eastmoney/test
```
## 🔄 降级机制详解
以 Failover 模式获取 K线为例
```
请求: GET /api/stocks/daily?code=600519&start=2026-01-01&end=2026-06-15
① 尝试 eastmoney (优先级1)
→ 失败(网络/解析错误)
→ 重试 2 次,仍失败
② 自动降级到 sina (优先级2)
→ 请求成功 ✅
→ 返回数据
如果 sina 也失败:
③ 自动降级到 tencent (优先级3)
→ 请求成功 ✅
如果全部失败:
④ 最终降级到 mock (优先级99)
→ 返回模拟数据
→ 保证系统不报错
```
## 📈 健康状态
每个数据源维护以下指标:
| 指标 | 说明 |
|------|------|
| `status` | healthy / degraded / down / unknown |
| `request_count` | 总请求数 |
| `success_count` | 成功次数 |
| `success_rate` | 成功率 |
| `avg_latency_ms` | 平均延迟 |
| `last_success` | 最后成功时间 |
| `last_error` | 最后错误信息 |
**自动状态判定规则**
- `healthy`: 成功率 > 90%
- `degraded`: 成功率 50%-90%
- `down`: 成功率 < 50% 且请求 > 5 次
## 🛠️ 扩展新数据源
### 1. 实现 DataSource trait
```rust
// src/services/sources/my_source.rs
use crate::services::traits::DataSource;
pub struct MySource { /* ... */ }
#[async_trait]
impl DataSource for MySource {
fn name(&self) -> &str { "mysource" }
fn source_type(&self) -> &'static str { "mysource" }
async fn health_check(&self) -> anyhow::Result<bool> { /* ... */ }
fn supports_daily(&self) -> bool { true }
async fn fetch_daily_quotes(&self, code: &str, start: NaiveDate, end: NaiveDate)
-> anyhow::Result<Vec<StockDaily>> { /* ... */ }
}
```
### 2. 注册到管理器
```rust
// src/services/sources/mod.rs
pub mod my_source;
// src/services/manager.rs DataSourceManager::new()
match src_cfg.source_type {
SourceType::MySource => Arc::new(MySource::new(timeout)),
}
```
### 3. 添加配置
```rust
// src/services/config.rs
pub enum SourceType {
MySource,
}
```
## 🚀 快速测试
```bash
# 启动后端
cd backend && ./start.sh
# 测试公司列表
curl "http://localhost:8080/api/companies?page=1&page_size=5"
# 测试K线真实数据
curl "http://localhost:8080/api/stocks/daily?code=600519&start=2026-01-01&end=2026-06-15"
# 测试实时行情
curl "http://localhost:8080/api/stocks/latest?codes=000100,600519"
# 查看数据源状态
curl "http://localhost:8080/api/datasources"
```