Files
trade/data/exchanges/base.ts
T
Rekey 1adb093100 refactor(data/exchanges): 多子类架构 + 工厂入口
- 每个交易所独立子类:BinanceRestClient extends BaseRestClient
- 统一入口 createRestClient(exchangeId) 工厂函数
- KLINE_INTERVAL_MS 移至 constants.ts
- fetchKlines 签名统一为 (symbol, startTime, limit?, endTime?)
- throttle 限流实际生效
- convertBinanceKline interval 参数化
- 删除 filterConsecutive 死代码
- 更新 run/exchange.ts 和 service/bnkline.ts 调用方
2026-06-16 17:53:36 +08:00

108 lines
4.1 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.
// ============================================================
// base.ts — REST 客户端抽象基类
// ============================================================
// 各交易所适配器继承此类,复用 REST 请求限流、重试等通用逻辑。
// 子类通过注入各交易所原生 SDKbinance / okx / bybit ...
// 实现具体的数据拉取,无需依赖 ccxt。
//
// 子类只需实现:
// - fetchKlines() — 历史 K 线拉取(基于目标交易所 SDK)
// - fetchMarkets() — 交易对元数据拉取(用于自动注册交易对)
//
// WebSocket 实时行情由各适配器自行管理,不在此基类范围内。
// ============================================================
import { logger } from "../utils/logger";
import type { Kline, MarketInfo, RestClientConfig } from "../types";
import { DEFAULT_REST_CONFIG } from "../types/base";
// ============================================================
// 工具:异步 sleep
// ============================================================
/** 返回一个在 ms 毫秒后 resolve 的 Promise */
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// ============================================================
// BaseRestClient
// ============================================================
export abstract class BaseRestClient {
/** 交易所标识(子类必须覆盖) */
abstract readonly exchange: string;
/** REST 客户端配置(可在子类构造函数中覆盖默认值) */
protected readonly config: RestClientConfig;
/** REST 请求节流 Mapkey → 上次请求时间戳) */
private lastRestFetch = new Map<string, number>();
// ============================================================
// 构造函数
// ============================================================
constructor(config: Partial<RestClientConfig> = {}) {
this.config = { ...DEFAULT_REST_CONFIG, ...config };
}
// ============================================================
// 限流工具
// ============================================================
/**
* 对同一 key 的 REST 请求进行冷却节流。
* 若距离上次请求不足 restRateLimitMs,自动等待剩余时间。
*
* @param key - 节流标识(如 `${symbol}:${interval}`
*/
protected async throttle(key: string): Promise<void> {
const lastFetch = this.lastRestFetch.get(key) ?? 0;
const elapsed = Date.now() - lastFetch;
if (elapsed < this.config.restRateLimitMs) {
const waitMs = this.config.restRateLimitMs - elapsed;
logger.debug(
{ exchange: this.exchange, key, waitMs },
`[${this.exchange}] REST 限流等待 ${waitMs}ms`,
);
await sleep(waitMs);
}
this.lastRestFetch.set(key, Date.now());
}
// ============================================================
// 抽象方法 —— 子类必须使用各自的交易所 SDK 实现
// ============================================================
/**
* 拉取 1m 历史 K 线数据(REST)。
*
* 子类负责:
* 1. 调用交易所原生 SDK 的 K 线接口
* 2. 将原始数据转换为本系统标准化 Kline 结构
* 3. 处理分页逻辑(若时间跨度超过单次请求上限)
*
* @param symbol - 交易对符号(如 BTCUSDT
* @param startTime - 起始时间(Unix ms
* @param limit - 单次最大条数(默认取自 config.defaultLimit
* @param endTime - 结束时间(Unix ms),可选
*/
abstract fetchKlines(
symbol: string,
startTime: number,
limit?: number,
endTime?: number,
): Promise<Kline[]>;
/**
* 获取交易所交易对信息(REST)。
*
* 子类负责调用交易所原生 SDK 的 /exchangeInfo 等价接口,
* 并转换为本系统标准化 MarketInfo 结构。
*/
abstract fetchMarkets(): Promise<MarketInfo[]>;
}
export default BaseRestClient;