// ============================================================ // trading-pair.entity.ts — 交易对配置实体 // ============================================================ // 映射到 PostgreSQL trading_pairs 表,存储各交易所的交易对元信息。 // 数据模块启动时从该表读取 active=true 的交易对列表, // 决定 WebSocket 订阅范围和 K 线合成范围。 // // 继承 CommonBaseEntity:id (UUID) / created_at / updated_at // // 与 TimescaleDB klines 表的关系: // klines.symbol → trading_pairs.symbol(逻辑外键,不做 DB 级约束) // klines.exchange → exchanges.name(逻辑外键) // ============================================================ import { Entity, Column, ManyToOne, JoinColumn, Index, } from "typeorm"; import { Exchange } from "./exchange.entity"; import { CommonBaseEntity } from "./common.entity"; import type { KlineInterval } from '../../types'; @Entity("trading_pairs") @Index(["exchange", "symbol"], { unique: true }) // 同一交易所下 symbol 唯一 @Index(["active"]) // 按激活状态快速筛选 export class TradingPair extends CommonBaseEntity { /** 所属交易所 */ @ManyToOne(() => Exchange, { nullable: false }) @JoinColumn({ name: "exchange_id" }) exchange!: Exchange; /** 交易对符号(如 BTCUSDT / ETHUSDT) */ @Column("varchar", { length: 20 }) symbol!: string; /** 基础币种(如 BTC) */ @Column("varchar", { length: 10 }) base_asset!: string; /** 计价币种(如 USDT) */ @Column("varchar", { length: 10 }) quote_asset!: string; /** 价格精度(小数位数) */ @Column("integer", { default: 10 }) price_precision!: number; /** 数量精度(小数位数) */ @Column("integer", { default: 10 }) quantity_precision!: number; /** 最小下单量 */ @Column("numeric", { precision: 32, scale: 8, nullable: true }) min_qty?: number; /** 下单步长(数量增量) */ @Column("numeric", { precision: 32, scale: 8, nullable: true }) step_size?: number; /** 最小名义价值(USDT) */ @Column("numeric", { precision: 32, scale: 8, nullable: true }) min_notional?: number; /** 是否激活数据订阅(false 时不采集该交易对行情) */ @Column("boolean", { default: true }) active!: boolean; /** 是否启用 K 线合成(false 时仅采集原始行情,不合成) */ @Column("boolean", { default: true }) kline_synthesis_enabled!: boolean; /** K 线时间周期 */ @Column("varchar", { length: 100, default: "1m" }) kline_interval!: KlineInterval; /** K 线合成周期列表(逗号分隔,如 "1m,5m,15m,1h,4h,1d") */ @Column("varchar", { length: 100, default: "1m,5m,15m,1h,4h,1d" }) kline_intervals!: string; /** * 历史 K 线最后补全时间(UTC)。 * 记录最近一次 REST 补拉 K 线的结束时间戳, * 下次启动时从此时间点继续补全,避免重复拉取。 * * 默认值为 Unix 0(1970-01-01T00:00:00.000Z), * 新交易对从 epoch 起始时间开始全量补拉, * 补全后更新为实际拉取到的最后时间。 */ @Column("timestamptz", { default: () => "to_timestamp(0)" }) last_backfill_time!: Date; /** 备注 */ @Column("text", { nullable: true }) notes?: string; // ============================================================ // 工具方法 // ============================================================ /** 解析 kline_intervals 为周期数组 */ getIntervals(): string[] { return this.kline_intervals .split(",") .map((s) => s.trim()) .filter(Boolean); } }