Files
one_divine_lot/docs/04-迭代记录/07-交易记录本地存储SQLite与策略关联/技术实现方案.md
T
kyugao 2aacd8a25d docs(迭代07/08): 交易记录本地存储 + 策略持仓展开全量文档 + 需求归档(R-009/R-010)
- PLAN-008/PLAN-009 计划(已完成)
- 迭代 07/08 四件套(目标/技术方案/验收标准/复盘)
- 设计约束:数据存储设计 §10/§10.1、技术约束-012/013、产品约束-008
- R-009/R-010 需求归档(含二次定稿:手动归属、Q4 成本价/成交价)
- 需求池索引同步
2026-09-02 01:21:10 +08:00

121 lines
5.8 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.
# 技术实现方案:07-交易记录本地存储(SQLite)+ 策略关联
> 依据:PLAN-008 需求:R-009(Q1-Q8 定稿)| 设计约束:技术约束-012(数据存储设计)、技术约束-011(测试隔离)
## 技术选型
- **存储**:沿用 SqliteStorenode:sqlite)——新增 trade_orders + trade_fills 两表(R-009 Q1);
- **同步**:服务端 TradeSync 模块(定时 60s + 启动预热 + 前端今日轮询写穿;UPSERT 幂等);
- **关联**:外键链推导(Q3 老师定稿):成交→委托(order_id 外键)→策略/holding(委托时间 join strategy_holdings 生命周期窗口)——两表零冗余 strategy_id/holding_id
- **历史查询**api/trades.js 新增 trades/history 端点(查本地 SQLite);
- **前端**TradeRecordsTab 加策略过滤 + 历史范围查本地。
## 表结构(数据存储设计.md §10 落实)
```sql
-- 交易委托(委托主行;order_id 唯一,UPSERT 幂等;零冗余 strategy_id/holding_id
CREATE TABLE IF NOT EXISTS trade_orders (
order_id TEXT PRIMARY KEY, -- m_strOrderSysID
trade_date TEXT NOT NULL, -- 交易日 YYYYMMDDm_strInsertDate
code TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
exchange TEXT NOT NULL DEFAULT '',
direction TEXT NOT NULL DEFAULT '', -- buy / sell
direction_code INTEGER,
opt_name TEXT NOT NULL DEFAULT '',
status INTEGER,
order_volume REAL NOT NULL DEFAULT 0,
traded_volume REAL NOT NULL DEFAULT 0,
limit_price REAL NOT NULL DEFAULT 0,
traded_price REAL NOT NULL DEFAULT 0,
amount REAL NOT NULL DEFAULT 0,
insert_date TEXT NOT NULL DEFAULT '',
insert_time TEXT NOT NULL DEFAULT '',
insert_ts INTEGER NOT NULL, -- 派生:insert_date+insert_time 合成毫秒时间戳(join 持仓窗口用)
cancel_info TEXT NOT NULL DEFAULT '',
error_msg TEXT NOT NULL DEFAULT '',
fetched_at INTEGER NOT NULL -- 同步时间戳
);
-- 交易成交(trade_id 唯一,order_id 外键关联委托;零冗余 strategy_id/holding_id
CREATE TABLE IF NOT EXISTS trade_fills (
trade_id TEXT PRIMARY KEY, -- m_strTradeID
order_id TEXT NOT NULL, -- → trade_orders.order_id
trade_date TEXT NOT NULL,
code TEXT NOT NULL,
name TEXT NOT NULL DEFAULT '',
exchange TEXT NOT NULL DEFAULT '',
direction TEXT NOT NULL DEFAULT '',
direction_code INTEGER,
opt_name TEXT NOT NULL DEFAULT '',
price REAL NOT NULL DEFAULT 0,
volume REAL NOT NULL DEFAULT 0,
amount REAL NOT NULL DEFAULT 0,
commission_rate_wan REAL NOT NULL DEFAULT 0,
trade_time TEXT NOT NULL DEFAULT '',
fetched_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_trade_orders_date ON trade_orders (trade_date);
CREATE INDEX IF NOT EXISTS idx_trade_orders_ts ON trade_orders (insert_ts);
CREATE INDEX IF NOT EXISTS idx_trade_fills_order ON trade_fills (order_id);
CREATE INDEX IF NOT EXISTS idx_trade_fills_date ON trade_fills (trade_date);
```
**策略归属推导(查询期,FK 链)**
- 委托归属:`trade_orders JOIN strategy_holdings ON o.code=h.code AND h.created_at <= o.insert_ts AND (h.closed_at IS NULL OR o.insert_ts < h.closed_at)`
- 一码多策略消歧:命中多笔持仓时取 shares 最大者(确定性规则);
- 成交归属 = 所属委托归属(fill → order → holding → strategy);
- 无命中 → 未关联(strategy_id 返回 null)。
## 架构设计
```
SqliteStore(改)
├─ init() 建表:+trade_orders/trade_fills + 索引
├─ upsertOrders(orders) / upsertFills(fills) # UPSERT 幂等
├─ getOrderHistory({start,end,code,strategyId,direction}) # 委托 + 策略归属推导
├─ getFillHistory({start,end,code,strategyId,direction}) # 成交(按委托归属 join)
└─ close()
DataStore(改)
└─ 委托交易记录方法(upsertTradeOrders/upsertTradeFills/queryTradeHistory
TradeSync(新增)
├─ start() : 启动预热同步一次 + 60s 定时
├─ syncNow() : 拉今日 orders+trades → upsertOrders/upsertFills(幂等)
└─ stop() : 清理定时器
api/trades.js(改)
└─ trades/history → storage.queryTradeHistory(时间段/code/策略/方向过滤)
index.js(改)
└─ 装配 TradeSyncdispose 停止)+ storage 注入 api runtime
client/views/TradeRecordsTab.jsx(改)
├─ 策略过滤下拉(全部/各策略/未关联)——今日实时过滤前端、历史走服务端过滤
└─ 历史范围:调 trades/history 查本地库(不再占位)
```
## 实现步骤
1. **文档骨架**PLAN-008 + 迭代 07(本步);
2. **设计约束**:数据存储设计.md §10 + 技术方案约束新增条目;
3. **SqliteStore**:建表 + upsertOrders/upsertFills + getOrderHistory/getFillHistory(策略归属 join);
4. **DataStore**:委托交易记录方法;
5. **TradeSync**:定时同步(60s + 启动预热 + UPSERT 幂等);
6. **api/trades.js**trades/history 端点;
7. **index.js**:装配 TradeSync + storage 注入 runtime
8. **前端**TradeRecordsTab 策略过滤 + 历史本地展示;
9. **构建测试**pnpm run build + typecheck + 独立数据目录回归(技术约束-011);
10. **验收 + 复盘**
## 涉及设计约束
| 约束 | 内容 |
|---|---|
| 技术约束-012 | 数据存储遵循数据存储设计.md(本迭代增补 §10 交易记录表设计) |
| 技术约束-011 | 测试/回归脚本禁止在真实数据上写操作:ODL_TEST_DATA_DIR 独立数据目录 |
| 技术约束-001/003/004/010 | 数据源抽象 / 直连 REST / webServer 自开路由 / 服务端中转+前端轮询(沿用) |
| 产品约束-007 | 方向语义红买绿卖(沿用 R-007) |