Files
trade/data/db/entities/kline.entity.ts
T
Rekey 5e385547c7 refactor(data): 重构交易所适配器,修复 Kline 实体复合主键
- 废弃旧 adapter 体系 (base/binance/types.ts),新增 base_rest/rest.ts
  基于 Binance 官方 SDK 实现 REST K 线拉取
- Kline 实体改为四列复合主键 (exchange/symbol/interval/time),
  修复单列 time PK 导致的跨 symbol 写入冲突
- 新增 filterConsecutive():K 线连续性过滤,首缺口截断策略
- 新增 service/kline.ts:批量 UPSERT K 线入库
- 新增 types/ 共享类型定义、example/ 示例、run/ 运行脚本
2026-06-08 18:18:16 +08:00

137 lines
4.5 KiB
TypeScript
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.
// ============================================================
// kline.entity.ts — TimescaleDB K 线 Hypertable 实体
// ============================================================
// 映射到 PostgreSQL klines 表(TimescaleDB hypertable)。
// 不继承 CommonBaseEntity — 使用 @timescaledb/typeorm 的
// @Hypertable / @TimeColumn 装饰器管理 TimescaleDB 特性。
//
// 关键 TimescaleDB 特性(由 @Hypertable 装饰器自动配置):
// - 自动按 time 列做时间分区(by_range
// - 列式压缩(compress),7 天后自动执行
// - 通过 ContinuousAggregate 生成高周期 K 线视图
//
// 注意:@timescaledb/typeorm v0.0.1 为实验版本,
// 不支持空间分区(partitioning_column)。
// 若需要空间分区,可通过 db/init-db/ 下的 SQL 脚本手动添加。
// ============================================================
import { Hypertable, TimeColumn } from "@timescaledb/typeorm";
import {
Entity,
PrimaryColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
} from "typeorm";
import type { KlineInterval } from '../../types';
/**
* 1 分钟 K 线 Hypertable
*
* 存储交易所推送的 OHLCV 数据。写入使用 UPSERT
* ON CONFLICT DO UPDATE),已存在的 K 线只更新
* high/low/close/volume 增量。
*
* 高周期 K 线(5m+)通过 TimescaleDB 连续聚合视图
* 从 1m 表自动生成,无需单独建表。
*/
@Hypertable({
compression: {
compress: true,
compress_orderby: "time DESC",
compress_segmentby: "exchange, symbol, interval",
policy: {
schedule_interval: "365 days", // 365 天后自动压缩
},
},
})
@Entity("klines")
export class Kline {
/**
* 复合主键:交易所 + 交易对 + 周期 + 时间
*
* 设计原因:
* - 不同 symbol 在同一时刻有各自的 K 线,单列 time PK 会导致跨 symbol 冲突
* - 四列复合主键 = 业务唯一性语义,同时满足 TimescaleDB hypertable 要求
* (分区列 time 必须包含在主键中)
* - 不再需要额外的 @Index unique — 复合主键已保证唯一性
*/
/** 交易所标识(binance / okx / bybit */
@PrimaryColumn("text")
exchange!: string;
/** 交易对符号(如 BTCUSDT */
@PrimaryColumn("text")
symbol!: string;
/** K 线周期(1m */
@PrimaryColumn("text")
interval!: KlineInterval;
/** K 线开盘时间(UTC)— @timescaledb/typeorm 自动标记为时间分区列 */
@TimeColumn()
@PrimaryColumn("timestamptz")
time!: Date;
// ============================================================
// OHLCV 价格数据(NUMERIC(20,8) 精度,与交易所对齐)
// ============================================================
/** 开盘价 */
@Column("numeric", { precision: 20, scale: 8 })
open!: number;
/** 最高价 */
@Column("numeric", { precision: 20, scale: 8 })
high!: number;
/** 最低价 */
@Column("numeric", { precision: 20, scale: 8 })
low!: number;
/** 收盘价 */
@Column("numeric", { precision: 20, scale: 8 })
close!: number;
/** 成交量(base 币种) */
@Column("numeric", { precision: 20, scale: 8 })
volume!: number;
// ============================================================
// 扩展字段(Binance 等交易所提供)
// ============================================================
/** 成交额(quote 币种) */
@Column("numeric", { precision: 20, scale: 8, nullable: true })
quote_volume?: number;
/** 主动买入成交量(base 币种) */
@Column("numeric", { precision: 20, scale: 8, nullable: true })
taker_buy_base_vol?: number;
/** 主动买入成交额(quote 币种) */
@Column("numeric", { precision: 20, scale: 8, nullable: true })
taker_buy_quote_vol?: number;
/** 成交笔数 */
@Column("integer", { nullable: true })
trade_count?: number;
/** K 线是否已关闭(true = 该周期 K 线不再变化) */
@Column("boolean", { default: true })
is_closed!: boolean;
// ============================================================
// 审计字段
// ============================================================
/** 记录首次写入时间 */
@CreateDateColumn({ type: "timestamptz", name: "created_at" })
createdAt!: Date;
/** 记录最后更新时间 */
@UpdateDateColumn({ type: "timestamptz", name: "updated_at" })
updatedAt!: Date;
}