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
+24 -16
View File
@@ -69,6 +69,9 @@ CREATE TABLE IF NOT EXISTS trading_pairs (
-- 交易对符号(如 BTCUSDT / ETHUSDT
symbol VARCHAR(20) NOT NULL,
-- 交易对类型(spot / um / cm
type TEXT NOT NULL DEFAULT 'spot',
-- 基础币种(如 BTC
base_asset VARCHAR(10) NOT NULL,
@@ -104,14 +107,14 @@ CREATE TABLE IF NOT EXISTS trading_pairs (
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
-- 同一交易所下 symbol 唯一
CONSTRAINT uq_trading_pairs_exchange_symbol UNIQUE (exchange_id, symbol)
-- 同一交易所下 symbol + type 唯一
CONSTRAINT uq_trading_pairs_exchange_symbol_type UNIQUE (exchange_id, symbol, type)
);
-- 按激活状态快速筛选
CREATE INDEX IF NOT EXISTS idx_trading_pairs_active ON trading_pairs (active);
-- 按交易所+交易对查询(最常用模式)
CREATE INDEX IF NOT EXISTS idx_trading_pairs_exchange_symbol ON trading_pairs (exchange_id, symbol);
CREATE INDEX IF NOT EXISTS idx_trading_pairs_exchange_symbol ON trading_pairs (exchange_id, symbol, type);
-- ============================================================
@@ -124,7 +127,7 @@ CREATE INDEX IF NOT EXISTS idx_trading_pairs_exchange_symbol ON trading_pairs (e
-- TimescaleDB 配置:
-- - chunk_time_interval: 7 days(周分区;1 day→7 days 减少 7× chunk 数)
-- - 列式压缩:7 天后自动执行(压缩率 ~92%)
-- - 压缩分段键:exchange, symbol(同交易对聚合压缩;interval 固定 1m 无需分段)
-- - 压缩分段键:exchange, symbol, type(同交易对+类型聚合压缩;interval 固定 1m 无需分段)
-- - 压缩排序键:time DESC(查询通常按时间降序)
--
-- chunk 大小选择指南(16GB / i3-7300U / 1TB SSD):
@@ -145,6 +148,9 @@ CREATE TABLE IF NOT EXISTS klines (
-- 交易对符号(如 BTCUSDT
symbol TEXT NOT NULL,
-- 交易对类型(spot / um / cm
type TEXT NOT NULL DEFAULT 'spot',
-- K 线周期(固定 "1m",基表仅存 1 分钟)
interval TEXT NOT NULL,
@@ -202,8 +208,8 @@ CREATE TABLE IF NOT EXISTS klines (
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
-- 复合主键:同一交易所、同一交易对、同一周期、同一时间的 K 线唯一
PRIMARY KEY (exchange, symbol, interval, time)
-- 复合主键:同一交易所、同一交易对、同一类型、同一周期、同一时间的 K 线唯一
PRIMARY KEY (exchange, symbol, type, interval, time)
);
-- ============================================================
@@ -222,10 +228,9 @@ SELECT create_hypertable('klines', 'time',
-- ============================================================
-- 启用列式压缩(先启用压缩,再设置分段/排序键)
-- 注意:interval 在基表固定为 '1m',从 segmentby 中移除以减少压缩分段数
ALTER TABLE klines SET (
timescaledb.compress,
timescaledb.compress_segmentby = 'exchange,symbol',
timescaledb.compress_segmentby = 'exchange,symbol,type',
timescaledb.compress_orderby = 'time DESC'
);
@@ -310,12 +315,13 @@ INSERT INTO exchanges (name, label, enabled, config) VALUES
'{"rateLimit": 600, "minOrderSize": 0.001, "feeTaker": 0.001, "feeMaker": 0.001}'::jsonb)
ON CONFLICT (name) DO NOTHING;
-- 默认交易对(仅 Binance 主流 USDT 永续合约,幂等)
INSERT INTO trading_pairs (exchange_id, symbol, base_asset, quote_asset,
-- 默认交易对(幂等)
INSERT INTO trading_pairs (exchange_id, symbol, type, base_asset, quote_asset,
price_precision, quantity_precision, active)
SELECT
e.id,
sym.symbol,
sym.type,
sym.base,
sym.quote,
2, -- price_precisionUSDT 计价通常 2 位小数)
@@ -324,10 +330,12 @@ SELECT
FROM exchanges e
CROSS JOIN (
VALUES
('BTCUSDT', 'BTC', 'USDT'),
('ETHUSDT', 'ETH', 'USDT'),
('BNBUSDT', 'BNB', 'USDT'),
('SOLUSDT', 'SOL', 'USDT')
) AS sym(symbol, base, quote)
('BTCUSDT', 'spot', 'BTC', 'USDT'),
('ETHUSDT', 'spot', 'ETH', 'USDT'),
('BNBUSDT', 'spot', 'BNB', 'USDT'),
('SOLUSDT', 'spot', 'SOL', 'USDT'),
('BTCUSDT', 'um', 'BTC', 'USDT'),
('ETHUSDT', 'um', 'ETH', 'USDT')
) AS sym(symbol, type, base, quote)
WHERE e.name = 'binance'
ON CONFLICT (exchange_id, symbol) DO NOTHING;
ON CONFLICT (exchange_id, symbol, type) DO NOTHING;