simpleEnv.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. import 'dotenv/config'
  2. /**
  3. * 简化的环境变量管理器
  4. * 统一处理所有环境变量读取,避免重复的 process.env 调用
  5. */
  6. export class SimpleEnv {
  7. /**
  8. * 获取环境变量值
  9. */
  10. static get(key, defaultValue) {
  11. if (this.cache.has(key)) {
  12. return this.cache.get(key)
  13. }
  14. const value = process.env[key] || defaultValue
  15. this.cache.set(key, value)
  16. return value
  17. }
  18. /**
  19. * 获取必需的环境变量值,如果不存在则抛出错误
  20. */
  21. static require(key) {
  22. const value = this.get(key)
  23. if (!value) {
  24. throw new Error(`Required environment variable ${key} is not set`)
  25. }
  26. return value
  27. }
  28. /**
  29. * 获取布尔值环境变量
  30. */
  31. static bool(key, defaultValue = false) {
  32. const value = this.get(key)
  33. if (!value) return defaultValue
  34. return ['true', '1', 'yes', 'on'].includes(value.toLowerCase())
  35. }
  36. /**
  37. * 获取数字环境变量
  38. */
  39. static number(key, defaultValue) {
  40. const value = this.get(key)
  41. if (!value) return defaultValue
  42. const num = parseInt(value, 10)
  43. return isNaN(num) ? defaultValue : num
  44. }
  45. /**
  46. * 获取 JSON 环境变量
  47. */
  48. static json(key, defaultValue) {
  49. const value = this.get(key)
  50. if (!value) return defaultValue
  51. try {
  52. return JSON.parse(value)
  53. } catch {
  54. return defaultValue
  55. }
  56. }
  57. /**
  58. * 获取数组环境变量(逗号分隔)
  59. */
  60. static array(key, defaultValue = []) {
  61. const value = this.get(key)
  62. if (!value) return defaultValue
  63. return value
  64. .split(',')
  65. .map(s => s.trim())
  66. .filter(s => s.length > 0)
  67. }
  68. /**
  69. * 清除缓存
  70. */
  71. static clearCache() {
  72. this.cache.clear()
  73. }
  74. /**
  75. * 批量获取带前缀的环境变量
  76. */
  77. static getPrefix(prefix) {
  78. const result = {}
  79. Object.keys(process.env).forEach(key => {
  80. if (key.startsWith(prefix)) {
  81. const shortKey = key.slice(prefix.length)
  82. const value = process.env[key]
  83. if (value) {
  84. result[shortKey] = value
  85. }
  86. }
  87. })
  88. return result
  89. }
  90. }
  91. SimpleEnv.cache = new Map()
  92. /**
  93. * 预定义的配置键,只包含需要从环境变量读取的配置
  94. */
  95. export const EnvKeys = {
  96. // 基础配置 (可选,有默认值)
  97. NODE_ENV: 'NODE_ENV',
  98. LOG_LEVEL: 'LOG_LEVEL',
  99. // Aster DEX 认证 (必需)
  100. ASTER_ORDER_USER: 'ASTER_ORDER_USER',
  101. ASTER_API_KEY: 'ASTER_API_KEY',
  102. ASTER_API_SECRET: 'ASTER_API_SECRET',
  103. // Aster 第二账户 (可选)
  104. ASTER2_ORDER_USER: 'ASTER2_ORDER_USER',
  105. ASTER2_ORDER_SIGNER: 'ASTER2_ORDER_SIGNER',
  106. PRIVATE_KEY2: 'PRIVATE_KEY2',
  107. // Pacifica DEX 认证 (必需)
  108. PACIFICA_ACCOUNT: 'PACIFICA_ACCOUNT',
  109. PACIFICA_ACCOUNT_PRIVATE_KEY: 'PACIFICA_ACCOUNT_PRIVATE_KEY',
  110. // 测试配置 (可选)
  111. PACIFICA_ENABLE_TEST_ORDER: 'PACIFICA_ENABLE_TEST_ORDER',
  112. PACIFICA_TEST_QTY: 'PACIFICA_TEST_QTY',
  113. // Binance (可选)
  114. BINANCE_API_KEY: 'BINANCE_API_KEY',
  115. BINANCE_SECRET_KEY: 'BINANCE_SECRET_KEY',
  116. // Proxy 配置 (可选)
  117. PROXY_ENABLED: 'PROXY_ENABLED',
  118. PROXY_PROTOCOL: 'PROXY_PROTOCOL',
  119. PROXY_HOST: 'PROXY_HOST',
  120. PROXY_PORT: 'PROXY_PORT',
  121. PROXY_USERNAME: 'PROXY_USERNAME',
  122. PROXY_PASSWORD: 'PROXY_PASSWORD',
  123. // 高级代理配置 (会话管理)
  124. PROXY_SESSION_PREFIX: 'PROXY_SESSION_PREFIX',
  125. PROXY_SESSION_SUFFIX: 'PROXY_SESSION_SUFFIX',
  126. PROXY_SESSION_STATIC: 'PROXY_SESSION_STATIC',
  127. // 交易所专用代理 (可选,优先级高于全局代理)
  128. ASTER_PROXY_PROTOCOL: 'ASTER_PROXY_PROTOCOL',
  129. ASTER_PROXY_HOST: 'ASTER_PROXY_HOST',
  130. ASTER_PROXY_PORT: 'ASTER_PROXY_PORT',
  131. ASTER_PROXY_USER: 'ASTER_PROXY_USER',
  132. ASTER_PROXY_PASS: 'ASTER_PROXY_PASS',
  133. ASTER_PROXY_SESSION_PREFIX: 'ASTER_PROXY_SESSION_PREFIX',
  134. ASTER_PROXY_SESSION_SUFFIX: 'ASTER_PROXY_SESSION_SUFFIX',
  135. ASTER_PROXY_SESSION_STATIC: 'ASTER_PROXY_SESSION_STATIC',
  136. // Pacifica专用代理
  137. PACIFICA_PROXY_PROTOCOL: 'PACIFICA_PROXY_PROTOCOL',
  138. PACIFICA_PROXY_HOST: 'PACIFICA_PROXY_HOST',
  139. PACIFICA_PROXY_PORT: 'PACIFICA_PROXY_PORT',
  140. PACIFICA_PROXY_USER: 'PACIFICA_PROXY_USER',
  141. PACIFICA_PROXY_PASS: 'PACIFICA_PROXY_PASS',
  142. PACIFICA_PROXY_SESSION_PREFIX: 'PACIFICA_PROXY_SESSION_PREFIX',
  143. PACIFICA_PROXY_SESSION_SUFFIX: 'PACIFICA_PROXY_SESSION_SUFFIX',
  144. PACIFICA_PROXY_SESSION_STATIC: 'PACIFICA_PROXY_SESSION_STATIC',
  145. // Binance专用代理
  146. BINANCE_PROXY_PROTOCOL: 'BINANCE_PROXY_PROTOCOL',
  147. BINANCE_PROXY_HOST: 'BINANCE_PROXY_HOST',
  148. BINANCE_PROXY_PORT: 'BINANCE_PROXY_PORT',
  149. BINANCE_PROXY_USER: 'BINANCE_PROXY_USER',
  150. BINANCE_PROXY_PASS: 'BINANCE_PROXY_PASS',
  151. BINANCE_PROXY_SESSION_PREFIX: 'BINANCE_PROXY_SESSION_PREFIX',
  152. BINANCE_PROXY_SESSION_SUFFIX: 'BINANCE_PROXY_SESSION_SUFFIX',
  153. BINANCE_PROXY_SESSION_STATIC: 'BINANCE_PROXY_SESSION_STATIC',
  154. }
  155. /**
  156. * 统一的配置对象 - 将固定配置写死,只有认证信息从环境变量读取
  157. */
  158. export const Config = {
  159. // 基础配置
  160. nodeEnv: () => SimpleEnv.get(EnvKeys.NODE_ENV, 'development'),
  161. logLevel: () => SimpleEnv.get(EnvKeys.LOG_LEVEL, 'info'),
  162. isDev: () => Config.nodeEnv() === 'development',
  163. isProd: () => Config.nodeEnv() === 'production',
  164. // Aster 配置 - 固定的服务端点,只有认证信息动态
  165. aster: {
  166. // 固定配置 - 不从环境变量读取
  167. wsUrl: 'wss://fstream.asterdex.com',
  168. httpBase: 'https://fapi.asterdex.com',
  169. subscribeSymbols: ['BTCUSDT', 'ETHUSDT'],
  170. wsPingInterval: 30000,
  171. wsPongTimeout: 10000,
  172. wsReconnectInterval: 5000,
  173. wsMaxReconnectAttempts: 10,
  174. recvWindow: 50000,
  175. // 动态配置 - 从环境变量读取
  176. orderUser: () => SimpleEnv.get(EnvKeys.ASTER_ORDER_USER),
  177. apiKey: () => SimpleEnv.get(EnvKeys.ASTER_API_KEY),
  178. apiSecret: () => SimpleEnv.get(EnvKeys.ASTER_API_SECRET),
  179. // 第二账户
  180. orderUser2: () => SimpleEnv.get(EnvKeys.ASTER2_ORDER_USER),
  181. orderSigner2: () => SimpleEnv.get(EnvKeys.ASTER2_ORDER_SIGNER),
  182. privateKey2: () => SimpleEnv.get(EnvKeys.PRIVATE_KEY2),
  183. },
  184. // Pacifica 配置 - 固定的服务端点,只有认证信息动态
  185. pacifica: {
  186. // 固定配置 - 不从环境变量读取
  187. baseUrl: 'https://api.pacifica.fi',
  188. wsUrl: 'wss://ws.pacifica.fi/ws',
  189. symbol: 'BTC-USD',
  190. defaultQty: 0.001,
  191. // 动态配置 - 从环境变量读取
  192. account: () => SimpleEnv.get(EnvKeys.PACIFICA_ACCOUNT),
  193. accountPrivateKey: () => SimpleEnv.get(EnvKeys.PACIFICA_ACCOUNT_PRIVATE_KEY),
  194. enableTestOrder: () => SimpleEnv.bool(EnvKeys.PACIFICA_ENABLE_TEST_ORDER, false),
  195. testQty: () => SimpleEnv.number(EnvKeys.PACIFICA_TEST_QTY, 0.001),
  196. },
  197. // Binance 配置 - 只有认证信息
  198. binance: {
  199. // 固定配置
  200. baseUrl: 'https://api.binance.com',
  201. wsUrl: 'wss://stream.binance.com:9443/ws',
  202. // 动态配置
  203. apiKey: () => SimpleEnv.get(EnvKeys.BINANCE_API_KEY),
  204. secretKey: () => SimpleEnv.get(EnvKeys.BINANCE_SECRET_KEY),
  205. },
  206. // Proxy 配置 - 支持全局和交易所专用代理
  207. proxy: {
  208. // 全局代理配置
  209. enabled: () => SimpleEnv.bool(EnvKeys.PROXY_ENABLED, false),
  210. protocol: () => SimpleEnv.get(EnvKeys.PROXY_PROTOCOL, 'http'),
  211. host: () => SimpleEnv.get(EnvKeys.PROXY_HOST),
  212. port: () => SimpleEnv.number(EnvKeys.PROXY_PORT, 8080),
  213. username: () => SimpleEnv.get(EnvKeys.PROXY_USERNAME),
  214. password: () => SimpleEnv.get(EnvKeys.PROXY_PASSWORD),
  215. // 会话管理 (高级功能)
  216. sessionPrefix: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_PREFIX),
  217. sessionSuffix: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_SUFFIX),
  218. sessionStatic: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_STATIC),
  219. // 交易所专用代理配置
  220. aster: {
  221. protocol: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_PROTOCOL, 'http'),
  222. host: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_HOST),
  223. port: () => SimpleEnv.number(EnvKeys.ASTER_PROXY_PORT, 12321),
  224. user: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_USER),
  225. pass: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_PASS),
  226. sessionPrefix: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_PREFIX),
  227. sessionSuffix: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_SUFFIX),
  228. sessionStatic: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_STATIC),
  229. isConfigured: () => {
  230. return !!Config.proxy.aster.host() && !!Config.proxy.aster.user()
  231. },
  232. },
  233. pacifica: {
  234. protocol: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_PROTOCOL, 'http'),
  235. host: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_HOST),
  236. port: () => SimpleEnv.number(EnvKeys.PACIFICA_PROXY_PORT, 8080),
  237. user: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_USER),
  238. pass: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_PASS),
  239. sessionPrefix: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_PREFIX),
  240. sessionSuffix: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_SUFFIX),
  241. sessionStatic: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_STATIC),
  242. isConfigured: () => {
  243. return !!Config.proxy.pacifica.host() && !!Config.proxy.pacifica.user()
  244. },
  245. },
  246. binance: {
  247. protocol: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_PROTOCOL, 'http'),
  248. host: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_HOST),
  249. port: () => SimpleEnv.number(EnvKeys.BINANCE_PROXY_PORT, 8080),
  250. user: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_USER),
  251. pass: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_PASS),
  252. sessionPrefix: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_PREFIX),
  253. sessionSuffix: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_SUFFIX),
  254. sessionStatic: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_STATIC),
  255. isConfigured: () => {
  256. return !!Config.proxy.binance.host() && !!Config.proxy.binance.user()
  257. },
  258. },
  259. // 生成随机会话ID (8位字符)
  260. generateSessionId: () => {
  261. const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
  262. let result = ''
  263. for (let i = 0; i < 8; i++) {
  264. result += chars.charAt(Math.floor(Math.random() * chars.length))
  265. }
  266. return result
  267. },
  268. // 构建代理密码 (支持会话管理)
  269. buildPassword: exchange => {
  270. let config
  271. // 优先使用交易所专用配置
  272. if (exchange === 'aster' && Config.proxy.aster.isConfigured()) {
  273. config = {
  274. pass: Config.proxy.aster.pass(),
  275. prefix: Config.proxy.aster.sessionPrefix(),
  276. suffix: Config.proxy.aster.sessionSuffix(),
  277. static: Config.proxy.aster.sessionStatic(),
  278. }
  279. } else if (exchange === 'pacifica' && Config.proxy.pacifica.isConfigured()) {
  280. config = {
  281. pass: Config.proxy.pacifica.pass(),
  282. prefix: Config.proxy.pacifica.sessionPrefix(),
  283. suffix: Config.proxy.pacifica.sessionSuffix(),
  284. static: Config.proxy.pacifica.sessionStatic(),
  285. }
  286. } else if (exchange === 'binance' && Config.proxy.binance.isConfigured()) {
  287. config = {
  288. pass: Config.proxy.binance.pass(),
  289. prefix: Config.proxy.binance.sessionPrefix(),
  290. suffix: Config.proxy.binance.sessionSuffix(),
  291. static: Config.proxy.binance.sessionStatic(),
  292. }
  293. } else {
  294. // 使用全局配置
  295. config = {
  296. pass: Config.proxy.password(),
  297. prefix: Config.proxy.sessionPrefix(),
  298. suffix: Config.proxy.sessionSuffix(),
  299. static: Config.proxy.sessionStatic(),
  300. }
  301. }
  302. // 方式一:直接使用完整密码
  303. if (config.pass) {
  304. return config.pass
  305. }
  306. // 方式二:使用前后缀+会话ID
  307. if (config.prefix && config.suffix) {
  308. const sessionId = config.static || Config.proxy.generateSessionId()
  309. return `${config.prefix}${sessionId}${config.suffix}`
  310. }
  311. return undefined
  312. },
  313. // 获取代理URL (支持交易所专用配置)
  314. getUrl: exchange => {
  315. let proxyConfig
  316. // 优先使用交易所专用代理
  317. if (exchange === 'aster' && Config.proxy.aster.isConfigured()) {
  318. proxyConfig = {
  319. protocol: Config.proxy.aster.protocol(),
  320. host: Config.proxy.aster.host(),
  321. port: Config.proxy.aster.port(),
  322. username: Config.proxy.aster.user(),
  323. password: Config.proxy.buildPassword('aster'),
  324. }
  325. } else if (exchange === 'pacifica' && Config.proxy.pacifica.isConfigured()) {
  326. proxyConfig = {
  327. protocol: Config.proxy.pacifica.protocol(),
  328. host: Config.proxy.pacifica.host(),
  329. port: Config.proxy.pacifica.port(),
  330. username: Config.proxy.pacifica.user(),
  331. password: Config.proxy.buildPassword('pacifica'),
  332. }
  333. } else if (exchange === 'binance' && Config.proxy.binance.isConfigured()) {
  334. proxyConfig = {
  335. protocol: Config.proxy.binance.protocol(),
  336. host: Config.proxy.binance.host(),
  337. port: Config.proxy.binance.port(),
  338. username: Config.proxy.binance.user(),
  339. password: Config.proxy.buildPassword('binance'),
  340. }
  341. } else if (Config.proxy.enabled() && Config.proxy.host()) {
  342. // 全局代理
  343. proxyConfig = {
  344. protocol: Config.proxy.protocol(),
  345. host: Config.proxy.host(),
  346. port: Config.proxy.port(),
  347. username: Config.proxy.username(),
  348. password: Config.proxy.buildPassword(),
  349. }
  350. } else {
  351. return undefined
  352. }
  353. const { protocol, host, port, username, password } = proxyConfig
  354. if (username && password) {
  355. return `${protocol}://${username}:${password}@${host}:${port}`
  356. } else {
  357. return `${protocol}://${host}:${port}`
  358. }
  359. },
  360. // 检查代理是否配置 (全局或交易所专用)
  361. isConfigured: exchange => {
  362. if (exchange === 'aster') {
  363. return Config.proxy.aster.isConfigured()
  364. } else if (exchange === 'pacifica') {
  365. return Config.proxy.pacifica.isConfigured()
  366. } else if (exchange === 'binance') {
  367. return Config.proxy.binance.isConfigured()
  368. }
  369. return Config.proxy.enabled() && !!Config.proxy.host()
  370. },
  371. // 检查任何代理是否配置
  372. isAnyConfigured: () => {
  373. return (
  374. Config.proxy.isConfigured() ||
  375. Config.proxy.aster.isConfigured() ||
  376. Config.proxy.pacifica.isConfigured() ||
  377. Config.proxy.binance.isConfigured()
  378. )
  379. },
  380. },
  381. // 获取所有配置(用于调试)
  382. getAll: () => ({
  383. nodeEnv: Config.nodeEnv(),
  384. logLevel: Config.logLevel(),
  385. aster: {
  386. wsUrl: Config.aster.wsUrl,
  387. httpBase: Config.aster.httpBase,
  388. subscribeSymbols: Config.aster.subscribeSymbols,
  389. orderUser: Config.aster.orderUser() ? '已设置' : '未设置',
  390. apiKey: Config.aster.apiKey() ? '已设置' : '未设置',
  391. },
  392. pacifica: {
  393. baseUrl: Config.pacifica.baseUrl,
  394. wsUrl: Config.pacifica.wsUrl,
  395. symbol: Config.pacifica.symbol,
  396. account: Config.pacifica.account() ? '已设置' : '未设置',
  397. enableTestOrder: Config.pacifica.enableTestOrder(),
  398. },
  399. binance: {
  400. baseUrl: Config.binance.baseUrl,
  401. wsUrl: Config.binance.wsUrl,
  402. apiKey: Config.binance.apiKey() ? '已设置' : '未设置',
  403. },
  404. proxy: {
  405. enabled: Config.proxy.enabled(),
  406. configured: Config.proxy.isConfigured(),
  407. url: Config.proxy.getUrl() ? '已配置' : '未配置',
  408. },
  409. }),
  410. }
  411. /**
  412. * 智能账户发现器 - 简化版
  413. */
  414. export class SmartAccountDiscovery {
  415. /**
  416. * 发现 Pacifica 账户
  417. */
  418. static discoverPacifica() {
  419. const accounts = []
  420. // 检查基础账户
  421. const baseAccount = SimpleEnv.get('PACIFICA_ACCOUNT')
  422. const baseKey = SimpleEnv.get('PACIFICA_ACCOUNT_PRIVATE_KEY')
  423. if (baseAccount && baseKey) {
  424. accounts.push({
  425. name: 'Pacifica Main',
  426. account: baseAccount,
  427. privateKey: baseKey,
  428. suffix: '',
  429. })
  430. }
  431. // 检查编号账户 (1-5)
  432. for (let i = 1; i <= 5; i++) {
  433. const account = SimpleEnv.get(`PACIFICA_ACCOUNT_${i}`)
  434. const key = SimpleEnv.get(`PACIFICA_PRIVATE_KEY_${i}`)
  435. if (account && key) {
  436. accounts.push({
  437. name: `Pacifica ${i}`,
  438. account,
  439. privateKey: key,
  440. suffix: `_${i}`,
  441. })
  442. }
  443. }
  444. // 检查角色账户
  445. const roles = ['MAIN', 'HEDGE', 'BACKUP']
  446. roles.forEach(role => {
  447. const account = SimpleEnv.get(`PACIFICA_ACCOUNT_${role}`)
  448. const key = SimpleEnv.get(`PACIFICA_PRIVATE_KEY_${role}`)
  449. if (account && key) {
  450. accounts.push({
  451. name: `Pacifica ${role.toLowerCase()}`,
  452. account,
  453. privateKey: key,
  454. suffix: `_${role}`,
  455. })
  456. }
  457. })
  458. return accounts
  459. }
  460. /**
  461. * 发现 Aster 账户
  462. */
  463. static discoverAster() {
  464. const accounts = []
  465. // 检查基础账户
  466. const baseUser = SimpleEnv.get('ASTER_ORDER_USER')
  467. const baseSigner = SimpleEnv.get('ASTER_ORDER_SIGNER')
  468. const baseKey = SimpleEnv.get('PRIVATE_KEY')
  469. if (baseUser && baseKey) {
  470. accounts.push({
  471. name: 'Aster Main',
  472. user: baseUser,
  473. signer: baseSigner,
  474. privateKey: baseKey,
  475. suffix: '',
  476. })
  477. }
  478. // 检查第二账户
  479. const user2 = SimpleEnv.get('ASTER2_ORDER_USER')
  480. const signer2 = SimpleEnv.get('ASTER2_ORDER_SIGNER')
  481. const key2 = SimpleEnv.get('PRIVATE_KEY2')
  482. if (user2 && key2) {
  483. accounts.push({
  484. name: 'Aster 2',
  485. user: user2,
  486. signer: signer2,
  487. privateKey: key2,
  488. suffix: '_2',
  489. })
  490. }
  491. // 检查编号账户 (1-3)
  492. for (let i = 1; i <= 3; i++) {
  493. const user = SimpleEnv.get(`ASTER_ORDER_USER_${i}`)
  494. const signer = SimpleEnv.get(`ASTER_ORDER_SIGNER_${i}`)
  495. const key = SimpleEnv.get(`ASTER_PRIVATE_KEY_${i}`)
  496. if (user && key) {
  497. accounts.push({
  498. name: `Aster ${i}`,
  499. user,
  500. signer,
  501. privateKey: key,
  502. suffix: `_${i}`,
  503. })
  504. }
  505. }
  506. return accounts
  507. }
  508. /**
  509. * 发现 Binance 账户
  510. */
  511. static discoverBinance() {
  512. const accounts = []
  513. // 检查基础账户
  514. const baseKey = SimpleEnv.get('BINANCE_API_KEY')
  515. const baseSecret = SimpleEnv.get('BINANCE_SECRET_KEY')
  516. if (baseKey && baseSecret) {
  517. accounts.push({
  518. name: 'Binance Main',
  519. apiKey: baseKey,
  520. secretKey: baseSecret,
  521. suffix: '',
  522. })
  523. }
  524. // 检查编号账户 (1-3)
  525. for (let i = 1; i <= 3; i++) {
  526. const key = SimpleEnv.get(`BINANCE_API_KEY_${i}`)
  527. const secret = SimpleEnv.get(`BINANCE_SECRET_KEY_${i}`)
  528. if (key && secret) {
  529. accounts.push({
  530. name: `Binance ${i}`,
  531. apiKey: key,
  532. secretKey: secret,
  533. suffix: `_${i}`,
  534. })
  535. }
  536. }
  537. return accounts
  538. }
  539. /**
  540. * 发现所有账户
  541. */
  542. static discoverAll() {
  543. return {
  544. pacifica: this.discoverPacifica(),
  545. aster: this.discoverAster(),
  546. binance: this.discoverBinance(),
  547. }
  548. }
  549. }