unified_account_manager_demo.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /**
  2. * 统一多账户管理系统演示
  3. * 展示多平台多账户的管理、对冲和监控功能
  4. */
  5. import 'dotenv/config'
  6. import { UnifiedAccountManager, AccountConfig } from '../src/accounts/UnifiedAccountManager'
  7. async function main() {
  8. console.log('🚀 统一多账户管理系统演示')
  9. try {
  10. // 1. 创建统一账户管理器
  11. console.log('\n🏗️ 创建统一账户管理器...')
  12. const manager = new UnifiedAccountManager({
  13. maxRetries: 3,
  14. timeoutMs: 30000,
  15. atomicTimeout: 5000,
  16. enableRollback: true,
  17. slippageTolerance: 0.005,
  18. positionSizeLimit: 1000,
  19. })
  20. // 2. 配置多个账户
  21. console.log('\n📝 配置账户...')
  22. // 检查可用的交易所凭证
  23. const hasAsterCredentials =
  24. process.env.ASTER_ORDER_USER && process.env.ASTER_API_KEY && process.env.ASTER_API_SECRET
  25. const hasPacificaCredentials = process.env.PACIFICA_ACCOUNT_PRIVATE_KEY && process.env.PACIFICA_ACCOUNT
  26. console.log(`✅ Aster 凭证: ${hasAsterCredentials ? '可用' : '不可用'}`)
  27. console.log(`✅ Pacifica 凭证: ${hasPacificaCredentials ? '可用' : '不可用'}`)
  28. // 使用优雅的账户配置系统
  29. const accountGroups = createAccountGroups()
  30. const accountConfigs = accountGroups.getActiveConfigs()
  31. if (accountConfigs.length === 0) {
  32. console.log('⚠️ 没有找到有效的 API 凭证,将以模拟模式运行')
  33. console.log('设置环境变量以启用真实账户连接:')
  34. console.log(' ASTER_ORDER_USER, ASTER_API_KEY, ASTER_API_SECRET (Aster DEX)')
  35. console.log(' PACIFICA_ACCOUNT, PACIFICA_ACCOUNT_PRIVATE_KEY (Pacifica)')
  36. // 运行模拟演示
  37. await runSimulationDemo(manager)
  38. return
  39. }
  40. // 3. 批量注册账户
  41. console.log('\n🔐 注册账户...')
  42. await manager.registerAccountsFromConfig(accountConfigs)
  43. // 4. 监听系统事件
  44. manager.on('account_registered', ({ accountKey, exchange }) => {
  45. console.log(`✅ 账户注册成功: ${accountKey} (${exchange})`)
  46. })
  47. manager.on('account_failed', ({ accountKey, error }) => {
  48. console.log(`❌ 账户失败: ${accountKey}, 错误: ${error.message}`)
  49. })
  50. manager.on('hedge_execution_completed', ({ accountKey, result }) => {
  51. console.log(`🎯 对冲完成: ${accountKey}, 数量: ${result.executedQuantity}`)
  52. })
  53. manager.on('system_stats_updated', stats => {
  54. console.log(`📊 系统统计更新: 总账户 ${stats.totalAccounts}, 在线 ${stats.onlineAccounts}`)
  55. })
  56. // 5. 等待初始化完成
  57. console.log('\n⏳ 等待账户初始化...')
  58. await new Promise(resolve => setTimeout(resolve, 3000))
  59. // 6. 获取聚合余额
  60. console.log('\n💰 获取聚合余额...')
  61. try {
  62. const balances = await manager.getAggregatedBalances()
  63. console.log('余额统计:')
  64. console.log(`📋 找到 ${Object.keys(balances).length} 种资产`)
  65. for (const [asset, balance] of Object.entries(balances)) {
  66. if (balance.total > 0.001) {
  67. // 只显示有意义的余额
  68. console.log(` ${asset}: ${balance.total.toFixed(8)} (${balance.accounts.length} 个账户)`)
  69. balance.accounts.forEach(account => {
  70. if (account.amount > 0.001) {
  71. console.log(` └─ ${account.accountKey}: ${account.amount.toFixed(8)}`)
  72. }
  73. })
  74. }
  75. }
  76. if (Object.keys(balances).length === 0) {
  77. console.log(' 暂无余额数据')
  78. }
  79. } catch (error) {
  80. console.log(`⚠️ 获取余额失败: ${error.message}`)
  81. }
  82. // 7. 获取聚合仓位
  83. console.log('\n📊 获取聚合仓位...')
  84. try {
  85. const positions = await manager.getAggregatedPositions()
  86. console.log('仓位统计:')
  87. console.log(`📋 找到 ${Object.keys(positions).length} 个交易对仓位`)
  88. for (const [symbol, position] of Object.entries(positions)) {
  89. if (Math.abs(position.netSize) > 0.001) {
  90. console.log(` ${symbol}: ${position.netSize.toFixed(6)} (净仓位, ${position.accounts.length} 个账户)`)
  91. position.accounts.forEach(account => {
  92. if (Math.abs(account.size) > 0.001) {
  93. console.log(` └─ ${account.accountKey}: ${account.size.toFixed(6)} (${account.side})`)
  94. }
  95. })
  96. }
  97. }
  98. if (Object.keys(positions).length === 0) {
  99. console.log(' 暂无仓位数据')
  100. }
  101. } catch (error) {
  102. console.log(`⚠️ 获取仓位失败: ${error.message}`)
  103. }
  104. // 8. 模拟智能路由下单
  105. console.log('\n🎯 模拟智能路由下单...')
  106. try {
  107. console.log('⚠️ 演示模式:不会执行真实交易')
  108. // 这里会选择最优账户进行下单
  109. console.log('智能路由会根据以下因素选择账户:')
  110. console.log(' - 账户优先级')
  111. console.log(' - 仓位限制')
  112. console.log(' - 日交易量限制')
  113. console.log(' - 账户健康状态')
  114. // 在真实环境中,这里会执行:
  115. // const result = await manager.smartRouteOrder({
  116. // symbol: 'BTCUSDT',
  117. // side: 'BUY',
  118. // type: 'MARKET',
  119. // quantity: '0.001'
  120. // });
  121. } catch (error) {
  122. console.log(`❌ 智能路由失败: ${error.message}`)
  123. }
  124. // 9. 显示系统统计
  125. console.log('\n📈 系统统计:')
  126. const stats = manager.getSystemStats()
  127. console.log(`总账户数: ${stats.accounts?.total || 0}`)
  128. console.log(`在线账户: ${stats.accounts?.online || 0}`)
  129. console.log(`离线账户: ${stats.accounts?.offline || 0}`)
  130. console.log(`错误账户: ${stats.accounts?.error || 0}`)
  131. console.log(`总权益: $${(stats.equity?.totalUsd || 0).toFixed(2)}`)
  132. console.log(`今日交易量: $${(stats.volume?.totalDailyUsd || 0).toFixed(2)}`)
  133. console.log(`对冲组数量: ${stats.hedgingGroups || 0}`)
  134. console.log(`对冲执行次数: ${stats.hedging?.totalExecutions || 0}`)
  135. console.log('\n🎯 跨账户对冲演示')
  136. console.log('系统会自动:')
  137. console.log(' - 检测仓位偏差')
  138. console.log(' - 选择最优对冲账户')
  139. console.log(' - 执行原子配对交易')
  140. console.log(' - 监控净敞口')
  141. console.log(' - 提供风险报告')
  142. // 10. 清理演示
  143. console.log('\n🧹 清理资源...')
  144. manager.destroy()
  145. console.log('\n🎉 演示完成')
  146. } catch (error) {
  147. console.error('❌ 演示失败:', error)
  148. }
  149. }
  150. /**
  151. * 优雅的账户分组配置系统
  152. * 支持批量配置、分组管理、环境变量自动检测
  153. */
  154. interface AccountGroup {
  155. name: string
  156. description: string
  157. accounts: AccountConfig[]
  158. enabled: boolean
  159. priority: number
  160. }
  161. class AccountGroupManager {
  162. private groups: Map<string, AccountGroup> = new Map()
  163. addGroup(name: string, group: Omit<AccountGroup, 'name'>): this {
  164. this.groups.set(name, { name, ...group })
  165. return this
  166. }
  167. getGroup(name: string): AccountGroup | undefined {
  168. return this.groups.get(name)
  169. }
  170. getActiveConfigs(): AccountConfig[] {
  171. const configs: AccountConfig[] = []
  172. // 按优先级排序组
  173. const sortedGroups = Array.from(this.groups.values())
  174. .filter(group => group.enabled)
  175. .sort((a, b) => a.priority - b.priority)
  176. for (const group of sortedGroups) {
  177. configs.push(...group.accounts.filter(account => account.enabled))
  178. }
  179. return configs
  180. }
  181. getGroupSummary(): { [groupName: string]: { total: number; active: number } } {
  182. const summary: { [groupName: string]: { total: number; active: number } } = {}
  183. for (const [name, group] of this.groups.entries()) {
  184. summary[name] = {
  185. total: group.accounts.length,
  186. active: group.enabled ? group.accounts.filter(account => account.enabled).length : 0,
  187. }
  188. }
  189. return summary
  190. }
  191. }
  192. /**
  193. * 创建账户分组配置
  194. */
  195. function createAccountGroups(): AccountGroupManager {
  196. const manager = new AccountGroupManager()
  197. // 主交易组 - 用于主要的交易和对冲
  198. const mainTradingAccounts: AccountConfig[] = []
  199. // Aster DEX 主账户 - 使用环境变量自动检测
  200. if (process.env.ASTER_ORDER_USER && process.env.ASTER_API_KEY && process.env.ASTER_API_SECRET) {
  201. mainTradingAccounts.push({
  202. exchange: 'aster',
  203. accountId: process.env.ASTER_ORDER_USER,
  204. alias: 'Aster主账户',
  205. enabled: true,
  206. priority: 1,
  207. tradingEnabled: true,
  208. hedgingEnabled: true,
  209. maxPositionUsd: 10000,
  210. maxDailyVolumeUsd: 100000,
  211. // 不需要显式 credentials,AdapterFactory 会从环境变量加载
  212. })
  213. }
  214. // Pacifica 主账户 - 使用环境变量自动检测
  215. if (process.env.PACIFICA_ACCOUNT && process.env.PACIFICA_ACCOUNT_PRIVATE_KEY) {
  216. mainTradingAccounts.push({
  217. exchange: 'pacifica',
  218. accountId: process.env.PACIFICA_ACCOUNT,
  219. alias: 'Pacifica主账户',
  220. enabled: true,
  221. priority: 2,
  222. tradingEnabled: true,
  223. hedgingEnabled: true,
  224. maxPositionUsd: 5000,
  225. maxDailyVolumeUsd: 50000,
  226. // 不需要显式 credentials,AdapterFactory 会从环境变量加载
  227. })
  228. }
  229. manager.addGroup('main_trading', {
  230. description: '主要交易账户组 - 用于核心交易和对冲策略',
  231. accounts: mainTradingAccounts,
  232. enabled: true,
  233. priority: 1,
  234. })
  235. // 测试账户组 - 用于测试和开发
  236. const testAccounts: AccountConfig[] = []
  237. // 可以在这里添加测试账户配置
  238. // if (process.env.ASTER_TEST_USER) { ... }
  239. manager.addGroup('testing', {
  240. description: '测试账户组 - 用于策略测试和开发',
  241. accounts: testAccounts,
  242. enabled: false, // 默认禁用测试账户
  243. priority: 9,
  244. })
  245. // 套利账户组 - 用于跨交易所套利
  246. const arbitrageAccounts: AccountConfig[] = []
  247. // 套利账户可以是同一交易所的多个账户,或者专门用于套利的账户
  248. // 这里可以添加专门的套利账户配置
  249. manager.addGroup('arbitrage', {
  250. description: '套利账户组 - 用于跨交易所套利策略',
  251. accounts: arbitrageAccounts,
  252. enabled: false, // 默认禁用,需要时手动启用
  253. priority: 5,
  254. })
  255. // 打印账户组信息
  256. const summary = manager.getGroupSummary()
  257. console.log('\n📊 账户组配置:')
  258. for (const [groupName, info] of Object.entries(summary)) {
  259. const group = manager.getGroup(groupName)!
  260. console.log(
  261. ` ${group.enabled ? '✅' : '❌'} ${groupName}: ${info.active}/${info.total} 账户活跃 - ${group.description}`,
  262. )
  263. }
  264. return manager
  265. }
  266. /**
  267. * 模拟演示 - 在没有真实 API 凭证时展示功能
  268. */
  269. async function runSimulationDemo(manager: UnifiedAccountManager) {
  270. console.log('\n🎭 模拟模式演示')
  271. // 模拟账户数据
  272. const mockAccounts = [
  273. {
  274. key: 'binance::main',
  275. exchange: 'binance',
  276. accountId: 'main',
  277. alias: 'Binance主账户',
  278. balances: [
  279. { asset: 'USDT', free: '1000.50', locked: '99.50', total: '1100.00' },
  280. { asset: 'BTC', free: '0.05234', locked: '0', total: '0.05234' },
  281. { asset: 'ETH', free: '1.2345', locked: '0.1', total: '1.3345' },
  282. ],
  283. positions: [
  284. { symbol: 'BTCUSDT', size: 0.025, side: 'long', unrealizedPnl: 125.3, entryPrice: 45000 },
  285. { symbol: 'ETHUSDT', size: -0.5, side: 'short', unrealizedPnl: -23.45, entryPrice: 3200 },
  286. ],
  287. equity: 3567.89,
  288. margin: 234.56,
  289. },
  290. {
  291. key: 'pacifica::demo',
  292. exchange: 'pacifica',
  293. accountId: 'demo',
  294. alias: 'Pacifica演示账户',
  295. balances: [
  296. { asset: 'USDT', free: '500.25', locked: '25.75', total: '526.00' },
  297. { asset: 'BTC', free: '0.01', locked: '0', total: '0.01' },
  298. ],
  299. positions: [{ symbol: 'BTCUSDT', size: 0.01, side: 'long', unrealizedPnl: 12.34, entryPrice: 44800 }],
  300. equity: 986.45,
  301. margin: 45.67,
  302. },
  303. ]
  304. console.log('\n💰 模拟聚合余额:')
  305. const aggregatedBalances = {
  306. USDT: { total: 1626.0, free: 1500.75, locked: 125.25 },
  307. BTC: { total: 0.06234, free: 0.06234, locked: 0 },
  308. ETH: { total: 1.3345, free: 1.2345, locked: 0.1 },
  309. }
  310. for (const [asset, balance] of Object.entries(aggregatedBalances)) {
  311. console.log(` ${asset}: ${balance.total.toFixed(8)} (可用: ${balance.free.toFixed(8)})`)
  312. }
  313. console.log('\n📊 模拟聚合仓位:')
  314. const aggregatedPositions = {
  315. BTCUSDT: { size: 0.035, side: 'long', unrealizedPnl: 137.64 },
  316. ETHUSDT: { size: -0.5, side: 'short', unrealizedPnl: -23.45 },
  317. }
  318. for (const [symbol, position] of Object.entries(aggregatedPositions)) {
  319. console.log(
  320. ` ${symbol}: ${position.size.toFixed(6)} (方向: ${position.side}, 未实现盈亏: ${position.unrealizedPnl.toFixed(
  321. 2,
  322. )})`,
  323. )
  324. }
  325. console.log('\n🎯 模拟智能路由决策:')
  326. console.log('场景: 需要在 BTCUSDT 上执行 0.01 BTC 的买单')
  327. console.log('分析结果:')
  328. console.log(' - Binance主账户: 优先级 1, 可用保证金充足, 日交易量限制内 ✅')
  329. console.log(' - Pacifica演示账户: 优先级 2, 可用保证金充足, 日交易量限制内 ✅')
  330. console.log('选择结果: Binance主账户 (优先级最高)')
  331. console.log('\n📈 模拟系统统计:')
  332. console.log(`总账户数: ${mockAccounts.length}`)
  333. console.log(`在线账户: ${mockAccounts.length}`)
  334. console.log(`总权益: $${(3567.89 + 986.45).toFixed(2)}`)
  335. console.log(`今日交易量: $12,345.67`)
  336. console.log(`活跃对冲会话: 0`)
  337. console.log('\n🎯 跨账户对冲场景演示:')
  338. console.log('检测到仓位偏差:')
  339. console.log(' - Binance: BTCUSDT +0.025 (多头过多)')
  340. console.log(' - Pacifica: BTCUSDT +0.01 (轻微多头)')
  341. console.log('对冲建议:')
  342. console.log(' - 在 Binance 开设 -0.01 BTCUSDT 空头仓位')
  343. console.log(' - 预期降低整体净敞口')
  344. console.log(' - 预计执行时间: 2-5秒')
  345. console.log('\n🔍 风险监控:')
  346. console.log(' ✅ 所有账户保证金率健康 (>150%)')
  347. console.log(' ✅ 日交易量限制内')
  348. console.log(' ⚠️ ETHUSDT 净敞口较大,建议关注')
  349. console.log(' ✅ 系统延迟正常 (<100ms)')
  350. console.log('\n🎉 模拟演示完成')
  351. console.log('\n💡 要使用真实数据,请设置以下环境变量:')
  352. console.log('export ASTER_ORDER_USER="your_user_address"')
  353. console.log('export ASTER_API_KEY="your_api_key"')
  354. console.log('export ASTER_API_SECRET="your_api_secret"')
  355. console.log('export PACIFICA_ACCOUNT="your_account_id"')
  356. console.log('export PACIFICA_ACCOUNT_PRIVATE_KEY="your_private_key"')
  357. }
  358. // 运行演示
  359. main().catch(console.error)