feat: 接入 USDT-M 合约数据 — type 字段方案

- PairType 定义移至 types/kline.ts (spot/um/cm)
- Kline 接口新增 type 字段,全链路透传
- klines 5列复合主键 (exchange, symbol, type, interval, time)
- 拆出 BinanceFuturesRestClient (USDMClient)
- exchanges/index.ts 注册 binance_futures
- trading_pairs 唯一约束加 type,种子数据加合约对
- 12个连续聚合视图 SELECT/GROUP BY/INDEX 加 type
- 清理 bnkline.ts 废弃代码和 pair.ts 空函数
This commit is contained in:
Rekey
2026-06-16 18:39:40 +08:00
parent 1adb093100
commit 705a2f6ea0
15 changed files with 442 additions and 209 deletions
+6 -5
View File
@@ -9,14 +9,14 @@ const repo = AppDataSource.getRepository(Kline);
* 批量 UPSERT K 线数据到 TimescaleDB。
*
* 映射应用层 KlineItem → 数据库实体,通过 INSERT ... ON CONFLICT DO UPDATE
* 实现幂等写入。冲突列为 [exchange, symbol, interval, time]列复合主键),
* 实现幂等写入。冲突列为 [exchange, symbol, type, interval, time]列复合主键),
* 冲突时更新 OHLCV 及扩展字段。
*
* 适用场景:
* - 回补历史 K 线(幂等,重复拉取不产生重复行)
* - WebSocket 实时 K 线增量刷新(更新最新一根未闭合 K 线的 high/low/close/volume
*
* 注意:依赖 Kline 实体的列复合主键 [exchange, symbol, interval, time]。
* 注意:依赖 Kline 实体的列复合主键 [exchange, symbol, type, interval, time]。
* 若实体 PK 结构变更,需同步更新 conflictPaths。
*
* @param KlineItems - 应用层标准化 K 线数组
@@ -35,6 +35,7 @@ export async function upsertOrUpdateKlines(KlineItems: KlineItem[]) {
entity.time = new Date(item.openTime); // Unix ms → Date
entity.exchange = item.exchange;
entity.symbol = item.symbol;
entity.type = item.type;
entity.interval = item.interval;
entity.open = Number(item.open);
entity.high = Number(item.high);
@@ -54,11 +55,11 @@ export async function upsertOrUpdateKlines(KlineItems: KlineItem[]) {
});
try {
// UPSERT: 冲突列匹配复合主键 [exchange, symbol, interval, time]
// 实体已改为列复合 PKON CONFLICT 直接命中主键约束
// UPSERT: 冲突列匹配复合主键 [exchange, symbol, type, interval, time]
// 实体已改为列复合 PKON CONFLICT 直接命中主键约束
// skipUpdateIfNoValuesChanged: 减少不必要的写操作
const result = await repo.upsert(entities, {
conflictPaths: ["exchange", "symbol", "interval", "time"],
conflictPaths: ["exchange", "symbol", "type", "interval", "time"],
skipUpdateIfNoValuesChanged: true,
});