feat(data): 实现 Binance WebSocket 适配器与架构重构
- 新增 exchanges/ 模块:MarketDataFeed 统一接口、BaseExchangeAdapter 抽象基类、 BinanceAdapter 完整实现(WebSocket + REST) - WebSocket 层基于 binance 官方 SDK 的 WebsocketClient,自动多路复用与断线重连 - REST 层使用 MainClient(Spot),实现 fetchKlines 自动分页补拉 + fetchMarkets 元数据解析 - 数据标准化:Ticker/Trade/OrderBook/Kline 类型定义与 Binance 原生格式互转 - 引入 RxJS Subject 作为统一事件流管道,按 eventType 运行时路由分发 - 重构 config/:YAML 驱动配置加载 + 零依赖运行时校验(fail-fast) - 重构 db/:TypeORM DataSource 配置 + TimescaleDB K 线 Hypertable 实体 - 新增 utils/logger.ts:Pino 结构化日志(开发环境 pino-pretty 彩色输出) - 新增 env.yaml 作为 TS/Python 共享的统一环境配置源 - 删除旧版手写 SQL schema 与散落配置文件,收敛到 TypeORM 实体管理 - 安装 rxjs@7.8.2 依赖
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
// ============================================================
|
||||
// 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";
|
||||
|
||||
@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 线合成周期列表(逗号分隔,如 "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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user