| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /**
- * 交易所适配器工厂
- * 统一管理适配器的创建、配置和初始化
- */
- import { ExchangeAdapter } from './ExchangeAdapter'
- import { BinanceAdapter } from './binance/BinanceAdapter'
- import { FutureConnector } from './binance/FutureConnector'
- import { PacificaAdapter } from './pacifica/PacificaAdapter'
- import { PacificaClient } from './pacifica/PacificaClient'
- import { AsterExchangeAdapter } from './aster/AsterExchangeAdapter'
- import { AsterAdapter } from './aster/asterAdapter'
- export type SupportedExchange = 'binance' | 'pacifica' | 'aster'
- export interface ExchangeConfig {
- exchange: SupportedExchange
- apiKey?: string
- apiSecret?: string
- baseUrl?: string
- wsUrl?: string
- privateKey?: string
- accountId?: string
- [key: string]: any
- }
- export interface AdapterFactoryResult {
- adapter: ExchangeAdapter
- config: ExchangeConfig
- initialized: boolean
- }
- export class AdapterFactory {
- private static instances = new Map<string, AdapterFactoryResult>()
- /**
- * 创建适配器实例
- */
- static async create(config: ExchangeConfig): Promise<AdapterFactoryResult> {
- const key = this.getInstanceKey(config)
- if (this.instances.has(key)) {
- return this.instances.get(key)!
- }
- const result = await this.createAdapter(config)
- this.instances.set(key, result)
- return result
- }
- /**
- * 从环境变量创建适配器
- */
- static async createFromEnv(exchange: SupportedExchange, accountId?: string): Promise<AdapterFactoryResult> {
- const config = this.loadConfigFromEnv(exchange, accountId)
- return this.create(config)
- }
- /**
- * 创建具体的适配器实例
- */
- private static async createAdapter(config: ExchangeConfig): Promise<AdapterFactoryResult> {
- let adapter: ExchangeAdapter
- let initialized = false
- try {
- switch (config.exchange) {
- case 'binance':
- adapter = await this.createBinanceAdapter(config)
- break
- case 'pacifica':
- adapter = await this.createPacificaAdapter(config)
- break
- case 'aster':
- adapter = await this.createAsterAdapter(config)
- break
- default:
- throw new Error(`不支持的交易所: ${config.exchange}`)
- }
- // 执行初始化测试
- initialized = await this.testAdapter(adapter, config.exchange)
- if (!initialized && config.exchange === 'pacifica') {
- // Pacifica 可能有网络问题,但仍然允许创建适配器
- console.warn(`⚠️ ${config.exchange} 适配器测试失败,但仍然创建实例`)
- initialized = true
- }
- return { adapter, config, initialized }
- } catch (error) {
- console.error(`❌ 创建 ${config.exchange} 适配器失败:`, error)
- // 对 Pacifica 的特殊处理
- if (config.exchange === 'pacifica' && error.message.includes('HTTP 500')) {
- console.warn(`⚠️ Pacifica 可能存在临时网络问题,跳过严格验证`)
- try {
- const adapter = await this.createPacificaAdapter(config)
- return { adapter, config, initialized: true }
- } catch (retryError) {
- console.error('❌ Pacifica 重试失败:', retryError)
- }
- }
- throw error
- }
- }
- /**
- * 创建币安适配器
- */
- private static async createBinanceAdapter(config: ExchangeConfig): Promise<BinanceAdapter> {
- if (!config.apiKey || !config.apiSecret) {
- throw new Error('Binance 适配器需要 apiKey 和 apiSecret')
- }
- const futureConnector = new FutureConnector(config.apiKey, config.apiSecret)
- return new BinanceAdapter(futureConnector)
- }
- /**
- * 创建Pacifica适配器
- */
- private static async createPacificaAdapter(config: ExchangeConfig): Promise<PacificaAdapter> {
- if (!config.privateKey || !config.accountId) {
- throw new Error('Pacifica 适配器需要 privateKey 和 accountId')
- }
- const client = new PacificaClient({
- baseUrl: config.baseUrl || 'https://api.pacifica.fi',
- wsUrl: config.wsUrl || 'wss://ws.pacifica.fi',
- account: config.accountId,
- privateKey: config.privateKey,
- agentWallet: config.agentWallet,
- agentPrivateKey: config.agentPrivateKey,
- })
- return new PacificaAdapter(client)
- }
- /**
- * 创建Aster适配器
- */
- private static async createAsterAdapter(config: ExchangeConfig): Promise<AsterExchangeAdapter> {
- if (!config.user || !config.signer || !config.privateKey) {
- throw new Error('Aster 适配器需要 user、signer 和 privateKey')
- }
- const asterConfig = {
- httpBase: config.baseUrl || 'https://fapi.asterdex.com',
- defaultUser: config.user,
- defaultSigner: config.signer,
- apiKey: config.apiKey,
- apiSecret: config.apiSecret,
- }
- const asterClient = new AsterAdapter(asterConfig)
- return new AsterExchangeAdapter(asterClient)
- }
- /**
- * 从环境变量加载配置
- */
- private static loadConfigFromEnv(exchange: SupportedExchange, accountId?: string): ExchangeConfig {
- switch (exchange) {
- case 'binance':
- return {
- exchange: 'binance',
- apiKey: process.env.BINANCE_API_KEY,
- apiSecret: process.env.BINANCE_SECRET_KEY,
- }
- case 'pacifica':
- return {
- exchange: 'pacifica',
- accountId: accountId || process.env.PACIFICA_ACCOUNT,
- privateKey: process.env.PACIFICA_ACCOUNT_PRIVATE_KEY || process.env.PACIFICA_PRIVATE_KEY,
- baseUrl: process.env.PACIFICA_BASE_URL,
- wsUrl: process.env.PACIFICA_WS_URL,
- agentWallet: process.env.PACIFICA_AGENT_WALLET,
- agentPrivateKey: process.env.PACIFICA_AGENT_PRIVATE_KEY,
- }
- case 'aster':
- return {
- exchange: 'aster',
- user: process.env.ASTER_ORDER_USER,
- signer: process.env.ASTER_ORDER_SIGNER || process.env.ASTER_API_KEY,
- privateKey: process.env.PRIVATE_KEY || process.env.PRIVATE_KEY2 || process.env.ASTER_API_SECRET,
- apiKey: process.env.ASTER_API_KEY,
- apiSecret: process.env.ASTER_API_SECRET,
- baseUrl: process.env.ASTER_HTTP_BASE,
- }
- default:
- throw new Error(`不支持的交易所: ${exchange}`)
- }
- }
- /**
- * 测试适配器基本功能
- */
- private static async testAdapter(adapter: ExchangeAdapter, exchange: string): Promise<boolean> {
- try {
- console.info(`🧪 测试 ${exchange} 适配器连接...`)
- // 基础连接测试
- const time = await adapter.time()
- if (!time || time <= 0) {
- console.warn(`⚠️ ${exchange} 时间同步测试失败`)
- return false
- }
- // 符号列表测试
- const symbols = await adapter.symbols()
- if (!Array.isArray(symbols)) {
- console.warn(`⚠️ ${exchange} 符号列表获取失败`)
- return false
- }
- console.info(`✅ ${exchange} 适配器测试通过 (获取到 ${symbols.length} 个交易对)`)
- return true
- } catch (error) {
- console.error(`❌ ${exchange} 适配器测试失败:`, error)
- return false
- }
- }
- /**
- * 生成实例缓存键
- */
- private static getInstanceKey(config: ExchangeConfig): string {
- const keyParts = [config.exchange]
- if (config.accountId) keyParts.push(config.accountId)
- if (config.user) keyParts.push(config.user)
- return keyParts.join('::')
- }
- /**
- * 清理所有适配器实例
- */
- static clearInstances(): void {
- this.instances.clear()
- }
- /**
- * 获取所有已创建的适配器
- */
- static getAllAdapters(): AdapterFactoryResult[] {
- return Array.from(this.instances.values())
- }
- /**
- * 健康检查所有适配器
- */
- static async healthCheck(): Promise<{ [exchange: string]: boolean }> {
- const results: { [exchange: string]: boolean } = {}
- for (const [key, { adapter, config }] of this.instances) {
- try {
- const isHealthy = await this.testAdapter(adapter, config.exchange)
- results[key] = isHealthy
- } catch {
- results[key] = false
- }
- }
- return results
- }
- }
|