股票数据模型
概述
股票数据模型用于存储和管理股票交易相关的数据,包括价格、成交量、时间戳等信息。系统支持多周期数据存储(1m/5m/1h/1d)和股票日历管理。
数据模型
StockData (股票数据)
| 字段名 | 类型 | 描述 | 示例 | 约束 |
|---|---|---|---|---|
| code | string | 股票代码 | “YINN.US” | 必填,唯一标识,包含市场后缀 |
| open | float | 开盘价 | 12.34 | 必填,≥0,保留2位小数 |
| high | float | 最高价 | 13.45 | 必填,≥0,保留2位小数 |
| low | float | 最低价 | 11.23 | 必填,≥0,保留2位小数 |
| close | float | 收盘价 | 12.78 | 必填,≥0,保留2位小数 |
| volume | int | 成交量 | 1000000 | 必填,≥0 |
| turnover | float | 成交额 | 12780000.00 | 必填,≥0,保留2位小数 |
| timestamp | int | 时间戳 | 1704067200 | 必填,UNIX时间戳 |
| trade_session | enum | 交易时段 | “Intraday” | 必填,见交易时段枚举 |
TradeSession (交易时段枚举)
| 值 | 描述 |
|---|---|
| Intraday | 盘中交易 |
| Pre | 盘前交易 |
| Post | 盘后交易 |
| Overnight | 夜盘交易 |
Period (时间周期枚举)
| 值 | 描述 | 存储方式 |
|---|---|---|
| 1m | 1分钟 | 预存储 |
| 5m | 5分钟 | 预存储 |
| 1h | 1小时 | 预存储(默认周期) |
| 1d | 日线 | 预存储 |
运行时聚合周期(从 1m 数据计算):2m, 3m, 10m, 15m, 30m, 2h, 3h, 4h, 1w, 1M, 1Q, 1Y
StockCalendarEntry (股票日历条目)
记录某股票某天的市场状态和各周期数据状态。
| 字段名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
| symbol | string | 股票代码 | 必填 |
| date | date | 日期 | 必填 |
| market_status | MarketStatus | 市场状态 | 必填 |
| data_status_1m | DataStatus | 1分钟数据状态 | not_fetched |
| data_status_5m | DataStatus | 5分钟数据状态 | not_fetched |
| data_status_1h | DataStatus | 1小时数据状态 | not_fetched |
| data_status_1d | DataStatus | 日线数据状态 | not_fetched |
| bars_1m | int | 1分钟 bar 数量 | 0 |
| bars_5m | int | 5分钟 bar 数量 | 0 |
| bars_1h | int | 1小时 bar 数量 | 0 |
| bars_1d | int | 日线 bar 数量 | 0 |
| created_at | datetime | 创建时间 | 当前时间 |
| updated_at | datetime | 更新时间 | 当前时间 |
MarketStatus (市场状态枚举)
| 值 | 描述 |
|---|---|
| full_day | 全天交易 |
| half_day | 半日交易(如感恩节后一天) |
| closed | 休市 |
DataStatus (数据状态枚举)
| 值 | 描述 |
|---|---|
| complete | 数据完整 |
| fetching | 拉取中 |
| not_fetched | 未拉取 |
| partial | 部分拉取 |
| n/a | 不适用(休市日) |
数据存储
Redis存储结构(多周期)
# 股票数据(多周期格式)
stock_data:{period}:{symbol}:{timestamp} # 股票数据详情 (Hash)
stock_data:time_index:{period}:{symbol} # 时间索引 (ZSET)
stock_codes # 股票代码集合 (Set)
# 股票日历
stock_calendar:{symbol}:{date} # 日历条目 (Hash)
stock_calendar:missing:{period}:{symbol} # 缺失日期索引 (Set)
# 旧格式(向后兼容)
stock_data:{symbol}:{timestamp} # 旧格式数据键
stock_data:time_index:{symbol} # 旧格式时间索引
存储格式说明
- 多周期数据键格式:
stock_data:{period}:{symbol}:{timestamp}period: 数据周期(1m/5m/1h/1d)symbol: 股票代码(如:YINN.US)timestamp: UNIX 时间戳
-
向后兼容: 默认周期 1h 同时支持旧格式键
stock_data:{symbol}:{timestamp} - 数据存储类型: Redis Hash
- 使用
hset存储字段-值对 - 支持字段级别的访问和更新
- 使用
- 时间索引: Redis ZSET
- 使用 UNIX 时间戳作为 score
- 支持时间范围查询
- 日历条目: Redis Hash
- 记录市场状态和各周期数据状态
- 支持按日期快速查询
- 缺失索引: Redis Set
- 按周期记录缺失数据的日期
- 支持快速查询需要补全的日期
存储示例
多周期数据键: stock_data:1h:YINN.US:1726459200
Hash字段:
symbol: "YINN.US"
open: "12.34"
high: "13.45"
low: "11.23"
close: "12.78"
volume: "1000000"
turnover: "12780000.00"
timestamp: "1726459200"
trade_session: "Intraday"
时间索引: stock_data:time_index:1h:YINN.US
- Score:
1726459200(Unix时间戳) - Member:
1726459200
日历条目: stock_calendar:YINN.US:2025-09-16
Hash字段:
symbol: "YINN.US"
date: "2025-09-16"
market_status: "full_day"
data_status_1m: "complete"
data_status_5m: "complete"
data_status_1h: "complete"
data_status_1d: "complete"
bars_1m: "390"
bars_5m: "78"
bars_1h: "7"
bars_1d: "1"
created_at: "2025-09-16T00:00:00"
updated_at: "2025-09-16T16:00:00"
缺失索引: stock_calendar:missing:1h:YINN.US
- Member:
2025-09-15,2025-09-14, …
API接口
股票数据接口
创建股票数据
- POST
/api/v1/stock-data - 请求体: StockDataCreate
- 响应:
{"message": "股票数据创建成功", "success": true}
获取股票数据列表
- GET
/api/v1/stock-data - 查询参数:
code: 股票代码筛选 (可选,格式:YINN.US)start_date: 开始日期(ISO格式,如:2025-09-16T00:00:00-04:00)(可选)end_date: 结束日期(ISO格式,如:2025-09-16T23:59:00-04:00)(可选)trade_session: 交易时段筛选 (可选)period: 数据周期: 1m/5m/1h/1d (默认: “1h”)sort_by: 排序字段 (默认: “timestamp”)sort_order: 排序方式: asc/desc (默认: “asc”)page: 页码 (默认: 1)page_size: 每页数量 (默认: 120, 最大: 1440)timezone: 时区 (默认: “Asia/Shanghai”)
- 响应: StockDataResponse
获取单条股票数据
- GET
/api/v1/stock-data/{code}/{timestamp} - 响应: StockData
获取股票代码列表
- GET
/api/v1/stock-codes - 响应: StockCodeList
删除股票数据
- DELETE
/api/v1/stock-data/{code} - 查询参数:
start_date: 开始日期(ISO格式)end_date: 结束日期(ISO格式)period: 数据周期: 1m/5m/1h/1d (可选,不指定则删除所有周期)timezone: 时区 (可选)
- 响应:
{"message": "股票数据删除成功", "success": true} - 说明: 删除数据时自动同步更新日历条目状态
数据导入接口
导入股票数据
- POST
/api/v1/stock-import/import - 请求体: StockImportRequest
symbol: 股票代码start_date: 开始日期(ISO格式,如:2025-09-16T00:00:00-04:00)end_date: 结束日期(ISO格式,如:2025-09-16T23:59:00-04:00)timezone: 时区(默认:America/New_York)periods: 要导入的周期列表 (可选,默认: [“1m”, “5m”, “1h”, “1d”])
- 响应: StockImportResponse
- 说明: 同一股票同时只能有一个导入任务
获取导入任务状态
- GET
/api/v1/stock-import/import/{task_id}/status - 响应: StockImportStatus
task_id: 任务IDstatus: 任务状态progress: 进度百分比message: 状态消息periods: 导入的周期列表period_results: 各周期导入结果
取消导入任务
- DELETE
/api/v1/stock-import/import/{task_id} - 响应:
{"message": "任务已取消", "success": true}
股票日历接口
初始化日历
- POST
/api/v1/stock-calendar/{symbol}/init - 请求体: InitCalendarRequest
start_date: 开始日期(ISO格式)end_date: 结束日期(ISO格式)
- 响应: InitCalendarResponse
success: 是否成功created_count: 创建的条目数skipped_count: 跳过的条目数(已存在)trading_days: 交易日数half_days: 半日交易数closed_days: 休市日数
- 说明: 从 LongPort API 获取交易日历,已存在的条目不会被覆盖(幂等性)
获取日历
- GET
/api/v1/stock-calendar/{symbol} - 查询参数:
start_date: 开始日期(ISO格式)end_date: 结束日期(ISO格式)
- 响应: GetCalendarResponse
entries: 日历条目列表total: 总条目数trading_days: 交易日数data_ready_days: 数据就绪天数
获取缺失日期
- GET
/api/v1/stock-calendar/{symbol}/missing - 查询参数:
period: 周期: 1m/5m/1h/1dstart_date: 开始日期(可选)end_date: 结束日期(可选)
- 响应: MissingDatesResponse
missing_dates: 缺失日期列表count: 缺失数量
验证数据完整性
- POST
/api/v1/stock-calendar/{symbol}/verify - 请求体: VerifyDataRequest
start_date: 开始日期(ISO格式)end_date: 结束日期(ISO格式)periods: 要验证的周期(可选,默认全部)
- 响应: VerifyDataResponse
is_ready: 数据是否就绪coverage_rate: 总覆盖率total_trading_days: 交易日总数ready_days: 数据就绪天数missing_dates: 缺失日期period_details: 各周期详情
WebSocket 实时日志
导入任务日志
- WebSocket
/ws/stock-import/{task_id} - 用途: 接收股票数据导入的实时日志和状态更新
数据同步日志
- WebSocket
/ws/data-sync/{task_id} - 用途: 接收 DataSyncService 的实时日志
- 消息格式:
{ "type": "log|status|error|success", "message": "日志消息", "timestamp": "2025-09-16T12:00:00", "sequence": 1 }
时区处理
支持的时区
Asia/Shanghai: 北京时间America/New_York: 美东时间 (自动处理夏令时/冬令时)
时区转换规则
- 前端时间格式: 使用ISO 8601格式带时区信息(如:2025-09-16T00:00:00-04:00)
- 后端存储: 统一转换为美东时间存储
- 查询转换: 根据用户选择的时区进行时间范围转换
- 数据导入: 支持按用户选择的时区进行数据获取和存储
时间格式示例
- 美东时间:
2025-09-16T00:00:00-04:00到2025-09-16T23:59:00-04:00 - 北京时间:
2025-09-16T00:00:00+08:00到2025-09-16T23:59:00+08:00
数据验证
价格字段验证
- 所有价格字段必须 ≥ 0
- 保留小数点后2位
- 开盘价、最高价、最低价、收盘价必须合理 (high ≥ max(open, close), low ≤ min(open, close))
时间戳验证
- 必须为有效的UNIX时间戳
- 不能为未来时间 (根据业务需求)
- 时间戳精度为秒级
交易时段验证
- 必须为有效的交易时段枚举值
- 根据时间戳自动推断交易时段 (可选)
性能优化
索引策略
- 按股票代码和周期建立时间索引
- 使用 ZSET 支持时间范围查询
- 使用 pipeline 批量操作减少网络往返
- 缺失索引支持快速查询需要补全的日期
数据持久化
- 股票数据永久存储,不设置 TTL
- 日历条目永久存储
- 依赖 Redis RDB + AOF 双重持久化保证数据安全
数据清理
手动清理
- 支持按时间范围删除
- 支持按周期删除(可指定 period 参数)
- 支持按股票代码删除
- 删除时自动同步更新日历条目状态
日历数据同步
- 删除股票数据时自动检查各周期剩余数据
- 如果某周期某天无数据,自动将日历状态更新为
not_fetched - 保证日历状态与实际数据一致