| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- import 'dotenv/config'
- /**
- * 简化的环境变量管理器
- * 统一处理所有环境变量读取,避免重复的 process.env 调用
- */
- export class SimpleEnv {
- /**
- * 获取环境变量值
- */
- static get(key, defaultValue) {
- if (this.cache.has(key)) {
- return this.cache.get(key)
- }
- const value = process.env[key] || defaultValue
- this.cache.set(key, value)
- return value
- }
- /**
- * 获取必需的环境变量值,如果不存在则抛出错误
- */
- static require(key) {
- const value = this.get(key)
- if (!value) {
- throw new Error(`Required environment variable ${key} is not set`)
- }
- return value
- }
- /**
- * 获取布尔值环境变量
- */
- static bool(key, defaultValue = false) {
- const value = this.get(key)
- if (!value) return defaultValue
- return ['true', '1', 'yes', 'on'].includes(value.toLowerCase())
- }
- /**
- * 获取数字环境变量
- */
- static number(key, defaultValue) {
- const value = this.get(key)
- if (!value) return defaultValue
- const num = parseInt(value, 10)
- return isNaN(num) ? defaultValue : num
- }
- /**
- * 获取 JSON 环境变量
- */
- static json(key, defaultValue) {
- const value = this.get(key)
- if (!value) return defaultValue
- try {
- return JSON.parse(value)
- } catch {
- return defaultValue
- }
- }
- /**
- * 获取数组环境变量(逗号分隔)
- */
- static array(key, defaultValue = []) {
- const value = this.get(key)
- if (!value) return defaultValue
- return value
- .split(',')
- .map(s => s.trim())
- .filter(s => s.length > 0)
- }
- /**
- * 清除缓存
- */
- static clearCache() {
- this.cache.clear()
- }
- /**
- * 批量获取带前缀的环境变量
- */
- static getPrefix(prefix) {
- const result = {}
- Object.keys(process.env).forEach(key => {
- if (key.startsWith(prefix)) {
- const shortKey = key.slice(prefix.length)
- const value = process.env[key]
- if (value) {
- result[shortKey] = value
- }
- }
- })
- return result
- }
- }
- SimpleEnv.cache = new Map()
- /**
- * 预定义的配置键,只包含需要从环境变量读取的配置
- */
- export const EnvKeys = {
- // 基础配置 (可选,有默认值)
- NODE_ENV: 'NODE_ENV',
- LOG_LEVEL: 'LOG_LEVEL',
- // Aster DEX 认证 (必需)
- ASTER_ORDER_USER: 'ASTER_ORDER_USER',
- ASTER_API_KEY: 'ASTER_API_KEY',
- ASTER_API_SECRET: 'ASTER_API_SECRET',
- // Aster 第二账户 (可选)
- ASTER2_ORDER_USER: 'ASTER2_ORDER_USER',
- ASTER2_ORDER_SIGNER: 'ASTER2_ORDER_SIGNER',
- PRIVATE_KEY2: 'PRIVATE_KEY2',
- // Pacifica DEX 认证 (必需)
- PACIFICA_ACCOUNT: 'PACIFICA_ACCOUNT',
- PACIFICA_ACCOUNT_PRIVATE_KEY: 'PACIFICA_ACCOUNT_PRIVATE_KEY',
- // 测试配置 (可选)
- PACIFICA_ENABLE_TEST_ORDER: 'PACIFICA_ENABLE_TEST_ORDER',
- PACIFICA_TEST_QTY: 'PACIFICA_TEST_QTY',
- // Binance (可选)
- BINANCE_API_KEY: 'BINANCE_API_KEY',
- BINANCE_SECRET_KEY: 'BINANCE_SECRET_KEY',
- // Proxy 配置 (可选)
- PROXY_ENABLED: 'PROXY_ENABLED',
- PROXY_PROTOCOL: 'PROXY_PROTOCOL',
- PROXY_HOST: 'PROXY_HOST',
- PROXY_PORT: 'PROXY_PORT',
- PROXY_USERNAME: 'PROXY_USERNAME',
- PROXY_PASSWORD: 'PROXY_PASSWORD',
- // 高级代理配置 (会话管理)
- PROXY_SESSION_PREFIX: 'PROXY_SESSION_PREFIX',
- PROXY_SESSION_SUFFIX: 'PROXY_SESSION_SUFFIX',
- PROXY_SESSION_STATIC: 'PROXY_SESSION_STATIC',
- // 交易所专用代理 (可选,优先级高于全局代理)
- ASTER_PROXY_PROTOCOL: 'ASTER_PROXY_PROTOCOL',
- ASTER_PROXY_HOST: 'ASTER_PROXY_HOST',
- ASTER_PROXY_PORT: 'ASTER_PROXY_PORT',
- ASTER_PROXY_USER: 'ASTER_PROXY_USER',
- ASTER_PROXY_PASS: 'ASTER_PROXY_PASS',
- ASTER_PROXY_SESSION_PREFIX: 'ASTER_PROXY_SESSION_PREFIX',
- ASTER_PROXY_SESSION_SUFFIX: 'ASTER_PROXY_SESSION_SUFFIX',
- ASTER_PROXY_SESSION_STATIC: 'ASTER_PROXY_SESSION_STATIC',
- // Pacifica专用代理
- PACIFICA_PROXY_PROTOCOL: 'PACIFICA_PROXY_PROTOCOL',
- PACIFICA_PROXY_HOST: 'PACIFICA_PROXY_HOST',
- PACIFICA_PROXY_PORT: 'PACIFICA_PROXY_PORT',
- PACIFICA_PROXY_USER: 'PACIFICA_PROXY_USER',
- PACIFICA_PROXY_PASS: 'PACIFICA_PROXY_PASS',
- PACIFICA_PROXY_SESSION_PREFIX: 'PACIFICA_PROXY_SESSION_PREFIX',
- PACIFICA_PROXY_SESSION_SUFFIX: 'PACIFICA_PROXY_SESSION_SUFFIX',
- PACIFICA_PROXY_SESSION_STATIC: 'PACIFICA_PROXY_SESSION_STATIC',
- // Binance专用代理
- BINANCE_PROXY_PROTOCOL: 'BINANCE_PROXY_PROTOCOL',
- BINANCE_PROXY_HOST: 'BINANCE_PROXY_HOST',
- BINANCE_PROXY_PORT: 'BINANCE_PROXY_PORT',
- BINANCE_PROXY_USER: 'BINANCE_PROXY_USER',
- BINANCE_PROXY_PASS: 'BINANCE_PROXY_PASS',
- BINANCE_PROXY_SESSION_PREFIX: 'BINANCE_PROXY_SESSION_PREFIX',
- BINANCE_PROXY_SESSION_SUFFIX: 'BINANCE_PROXY_SESSION_SUFFIX',
- BINANCE_PROXY_SESSION_STATIC: 'BINANCE_PROXY_SESSION_STATIC',
- }
- /**
- * 统一的配置对象 - 将固定配置写死,只有认证信息从环境变量读取
- */
- export const Config = {
- // 基础配置
- nodeEnv: () => SimpleEnv.get(EnvKeys.NODE_ENV, 'development'),
- logLevel: () => SimpleEnv.get(EnvKeys.LOG_LEVEL, 'info'),
- isDev: () => Config.nodeEnv() === 'development',
- isProd: () => Config.nodeEnv() === 'production',
- // Aster 配置 - 固定的服务端点,只有认证信息动态
- aster: {
- // 固定配置 - 不从环境变量读取
- wsUrl: 'wss://fstream.asterdex.com',
- httpBase: 'https://fapi.asterdex.com',
- subscribeSymbols: ['BTCUSDT', 'ETHUSDT'],
- wsPingInterval: 30000,
- wsPongTimeout: 10000,
- wsReconnectInterval: 5000,
- wsMaxReconnectAttempts: 10,
- recvWindow: 50000,
- // 动态配置 - 从环境变量读取
- orderUser: () => SimpleEnv.get(EnvKeys.ASTER_ORDER_USER),
- apiKey: () => SimpleEnv.get(EnvKeys.ASTER_API_KEY),
- apiSecret: () => SimpleEnv.get(EnvKeys.ASTER_API_SECRET),
- // 第二账户
- orderUser2: () => SimpleEnv.get(EnvKeys.ASTER2_ORDER_USER),
- orderSigner2: () => SimpleEnv.get(EnvKeys.ASTER2_ORDER_SIGNER),
- privateKey2: () => SimpleEnv.get(EnvKeys.PRIVATE_KEY2),
- },
- // Pacifica 配置 - 固定的服务端点,只有认证信息动态
- pacifica: {
- // 固定配置 - 不从环境变量读取
- baseUrl: 'https://api.pacifica.fi',
- wsUrl: 'wss://ws.pacifica.fi/ws',
- symbol: 'BTC-USD',
- defaultQty: 0.001,
- // 动态配置 - 从环境变量读取
- account: () => SimpleEnv.get(EnvKeys.PACIFICA_ACCOUNT),
- accountPrivateKey: () => SimpleEnv.get(EnvKeys.PACIFICA_ACCOUNT_PRIVATE_KEY),
- enableTestOrder: () => SimpleEnv.bool(EnvKeys.PACIFICA_ENABLE_TEST_ORDER, false),
- testQty: () => SimpleEnv.number(EnvKeys.PACIFICA_TEST_QTY, 0.001),
- },
- // Binance 配置 - 只有认证信息
- binance: {
- // 固定配置
- baseUrl: 'https://api.binance.com',
- wsUrl: 'wss://stream.binance.com:9443/ws',
- // 动态配置
- apiKey: () => SimpleEnv.get(EnvKeys.BINANCE_API_KEY),
- secretKey: () => SimpleEnv.get(EnvKeys.BINANCE_SECRET_KEY),
- },
- // Proxy 配置 - 支持全局和交易所专用代理
- proxy: {
- // 全局代理配置
- enabled: () => SimpleEnv.bool(EnvKeys.PROXY_ENABLED, false),
- protocol: () => SimpleEnv.get(EnvKeys.PROXY_PROTOCOL, 'http'),
- host: () => SimpleEnv.get(EnvKeys.PROXY_HOST),
- port: () => SimpleEnv.number(EnvKeys.PROXY_PORT, 8080),
- username: () => SimpleEnv.get(EnvKeys.PROXY_USERNAME),
- password: () => SimpleEnv.get(EnvKeys.PROXY_PASSWORD),
- // 会话管理 (高级功能)
- sessionPrefix: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_PREFIX),
- sessionSuffix: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_SUFFIX),
- sessionStatic: () => SimpleEnv.get(EnvKeys.PROXY_SESSION_STATIC),
- // 交易所专用代理配置
- aster: {
- protocol: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_PROTOCOL, 'http'),
- host: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_HOST),
- port: () => SimpleEnv.number(EnvKeys.ASTER_PROXY_PORT, 12321),
- user: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_USER),
- pass: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_PASS),
- sessionPrefix: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_PREFIX),
- sessionSuffix: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_SUFFIX),
- sessionStatic: () => SimpleEnv.get(EnvKeys.ASTER_PROXY_SESSION_STATIC),
- isConfigured: () => {
- return !!Config.proxy.aster.host() && !!Config.proxy.aster.user()
- },
- },
- pacifica: {
- protocol: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_PROTOCOL, 'http'),
- host: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_HOST),
- port: () => SimpleEnv.number(EnvKeys.PACIFICA_PROXY_PORT, 8080),
- user: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_USER),
- pass: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_PASS),
- sessionPrefix: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_PREFIX),
- sessionSuffix: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_SUFFIX),
- sessionStatic: () => SimpleEnv.get(EnvKeys.PACIFICA_PROXY_SESSION_STATIC),
- isConfigured: () => {
- return !!Config.proxy.pacifica.host() && !!Config.proxy.pacifica.user()
- },
- },
- binance: {
- protocol: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_PROTOCOL, 'http'),
- host: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_HOST),
- port: () => SimpleEnv.number(EnvKeys.BINANCE_PROXY_PORT, 8080),
- user: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_USER),
- pass: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_PASS),
- sessionPrefix: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_PREFIX),
- sessionSuffix: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_SUFFIX),
- sessionStatic: () => SimpleEnv.get(EnvKeys.BINANCE_PROXY_SESSION_STATIC),
- isConfigured: () => {
- return !!Config.proxy.binance.host() && !!Config.proxy.binance.user()
- },
- },
- // 生成随机会话ID (8位字符)
- generateSessionId: () => {
- const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
- let result = ''
- for (let i = 0; i < 8; i++) {
- result += chars.charAt(Math.floor(Math.random() * chars.length))
- }
- return result
- },
- // 构建代理密码 (支持会话管理)
- buildPassword: exchange => {
- let config
- // 优先使用交易所专用配置
- if (exchange === 'aster' && Config.proxy.aster.isConfigured()) {
- config = {
- pass: Config.proxy.aster.pass(),
- prefix: Config.proxy.aster.sessionPrefix(),
- suffix: Config.proxy.aster.sessionSuffix(),
- static: Config.proxy.aster.sessionStatic(),
- }
- } else if (exchange === 'pacifica' && Config.proxy.pacifica.isConfigured()) {
- config = {
- pass: Config.proxy.pacifica.pass(),
- prefix: Config.proxy.pacifica.sessionPrefix(),
- suffix: Config.proxy.pacifica.sessionSuffix(),
- static: Config.proxy.pacifica.sessionStatic(),
- }
- } else if (exchange === 'binance' && Config.proxy.binance.isConfigured()) {
- config = {
- pass: Config.proxy.binance.pass(),
- prefix: Config.proxy.binance.sessionPrefix(),
- suffix: Config.proxy.binance.sessionSuffix(),
- static: Config.proxy.binance.sessionStatic(),
- }
- } else {
- // 使用全局配置
- config = {
- pass: Config.proxy.password(),
- prefix: Config.proxy.sessionPrefix(),
- suffix: Config.proxy.sessionSuffix(),
- static: Config.proxy.sessionStatic(),
- }
- }
- // 方式一:直接使用完整密码
- if (config.pass) {
- return config.pass
- }
- // 方式二:使用前后缀+会话ID
- if (config.prefix && config.suffix) {
- const sessionId = config.static || Config.proxy.generateSessionId()
- return `${config.prefix}${sessionId}${config.suffix}`
- }
- return undefined
- },
- // 获取代理URL (支持交易所专用配置)
- getUrl: exchange => {
- let proxyConfig
- // 优先使用交易所专用代理
- if (exchange === 'aster' && Config.proxy.aster.isConfigured()) {
- proxyConfig = {
- protocol: Config.proxy.aster.protocol(),
- host: Config.proxy.aster.host(),
- port: Config.proxy.aster.port(),
- username: Config.proxy.aster.user(),
- password: Config.proxy.buildPassword('aster'),
- }
- } else if (exchange === 'pacifica' && Config.proxy.pacifica.isConfigured()) {
- proxyConfig = {
- protocol: Config.proxy.pacifica.protocol(),
- host: Config.proxy.pacifica.host(),
- port: Config.proxy.pacifica.port(),
- username: Config.proxy.pacifica.user(),
- password: Config.proxy.buildPassword('pacifica'),
- }
- } else if (exchange === 'binance' && Config.proxy.binance.isConfigured()) {
- proxyConfig = {
- protocol: Config.proxy.binance.protocol(),
- host: Config.proxy.binance.host(),
- port: Config.proxy.binance.port(),
- username: Config.proxy.binance.user(),
- password: Config.proxy.buildPassword('binance'),
- }
- } else if (Config.proxy.enabled() && Config.proxy.host()) {
- // 全局代理
- proxyConfig = {
- protocol: Config.proxy.protocol(),
- host: Config.proxy.host(),
- port: Config.proxy.port(),
- username: Config.proxy.username(),
- password: Config.proxy.buildPassword(),
- }
- } else {
- return undefined
- }
- const { protocol, host, port, username, password } = proxyConfig
- if (username && password) {
- return `${protocol}://${username}:${password}@${host}:${port}`
- } else {
- return `${protocol}://${host}:${port}`
- }
- },
- // 检查代理是否配置 (全局或交易所专用)
- isConfigured: exchange => {
- if (exchange === 'aster') {
- return Config.proxy.aster.isConfigured()
- } else if (exchange === 'pacifica') {
- return Config.proxy.pacifica.isConfigured()
- } else if (exchange === 'binance') {
- return Config.proxy.binance.isConfigured()
- }
- return Config.proxy.enabled() && !!Config.proxy.host()
- },
- // 检查任何代理是否配置
- isAnyConfigured: () => {
- return (
- Config.proxy.isConfigured() ||
- Config.proxy.aster.isConfigured() ||
- Config.proxy.pacifica.isConfigured() ||
- Config.proxy.binance.isConfigured()
- )
- },
- },
- // 获取所有配置(用于调试)
- getAll: () => ({
- nodeEnv: Config.nodeEnv(),
- logLevel: Config.logLevel(),
- aster: {
- wsUrl: Config.aster.wsUrl,
- httpBase: Config.aster.httpBase,
- subscribeSymbols: Config.aster.subscribeSymbols,
- orderUser: Config.aster.orderUser() ? '已设置' : '未设置',
- apiKey: Config.aster.apiKey() ? '已设置' : '未设置',
- },
- pacifica: {
- baseUrl: Config.pacifica.baseUrl,
- wsUrl: Config.pacifica.wsUrl,
- symbol: Config.pacifica.symbol,
- account: Config.pacifica.account() ? '已设置' : '未设置',
- enableTestOrder: Config.pacifica.enableTestOrder(),
- },
- binance: {
- baseUrl: Config.binance.baseUrl,
- wsUrl: Config.binance.wsUrl,
- apiKey: Config.binance.apiKey() ? '已设置' : '未设置',
- },
- proxy: {
- enabled: Config.proxy.enabled(),
- configured: Config.proxy.isConfigured(),
- url: Config.proxy.getUrl() ? '已配置' : '未配置',
- },
- }),
- }
- /**
- * 智能账户发现器 - 简化版
- */
- export class SmartAccountDiscovery {
- /**
- * 发现 Pacifica 账户
- */
- static discoverPacifica() {
- const accounts = []
- // 检查基础账户
- const baseAccount = SimpleEnv.get('PACIFICA_ACCOUNT')
- const baseKey = SimpleEnv.get('PACIFICA_ACCOUNT_PRIVATE_KEY')
- if (baseAccount && baseKey) {
- accounts.push({
- name: 'Pacifica Main',
- account: baseAccount,
- privateKey: baseKey,
- suffix: '',
- })
- }
- // 检查编号账户 (1-5)
- for (let i = 1; i <= 5; i++) {
- const account = SimpleEnv.get(`PACIFICA_ACCOUNT_${i}`)
- const key = SimpleEnv.get(`PACIFICA_PRIVATE_KEY_${i}`)
- if (account && key) {
- accounts.push({
- name: `Pacifica ${i}`,
- account,
- privateKey: key,
- suffix: `_${i}`,
- })
- }
- }
- // 检查角色账户
- const roles = ['MAIN', 'HEDGE', 'BACKUP']
- roles.forEach(role => {
- const account = SimpleEnv.get(`PACIFICA_ACCOUNT_${role}`)
- const key = SimpleEnv.get(`PACIFICA_PRIVATE_KEY_${role}`)
- if (account && key) {
- accounts.push({
- name: `Pacifica ${role.toLowerCase()}`,
- account,
- privateKey: key,
- suffix: `_${role}`,
- })
- }
- })
- return accounts
- }
- /**
- * 发现 Aster 账户
- */
- static discoverAster() {
- const accounts = []
- // 检查基础账户
- const baseUser = SimpleEnv.get('ASTER_ORDER_USER')
- const baseSigner = SimpleEnv.get('ASTER_ORDER_SIGNER')
- const baseKey = SimpleEnv.get('PRIVATE_KEY')
- if (baseUser && baseKey) {
- accounts.push({
- name: 'Aster Main',
- user: baseUser,
- signer: baseSigner,
- privateKey: baseKey,
- suffix: '',
- })
- }
- // 检查第二账户
- const user2 = SimpleEnv.get('ASTER2_ORDER_USER')
- const signer2 = SimpleEnv.get('ASTER2_ORDER_SIGNER')
- const key2 = SimpleEnv.get('PRIVATE_KEY2')
- if (user2 && key2) {
- accounts.push({
- name: 'Aster 2',
- user: user2,
- signer: signer2,
- privateKey: key2,
- suffix: '_2',
- })
- }
- // 检查编号账户 (1-3)
- for (let i = 1; i <= 3; i++) {
- const user = SimpleEnv.get(`ASTER_ORDER_USER_${i}`)
- const signer = SimpleEnv.get(`ASTER_ORDER_SIGNER_${i}`)
- const key = SimpleEnv.get(`ASTER_PRIVATE_KEY_${i}`)
- if (user && key) {
- accounts.push({
- name: `Aster ${i}`,
- user,
- signer,
- privateKey: key,
- suffix: `_${i}`,
- })
- }
- }
- return accounts
- }
- /**
- * 发现 Binance 账户
- */
- static discoverBinance() {
- const accounts = []
- // 检查基础账户
- const baseKey = SimpleEnv.get('BINANCE_API_KEY')
- const baseSecret = SimpleEnv.get('BINANCE_SECRET_KEY')
- if (baseKey && baseSecret) {
- accounts.push({
- name: 'Binance Main',
- apiKey: baseKey,
- secretKey: baseSecret,
- suffix: '',
- })
- }
- // 检查编号账户 (1-3)
- for (let i = 1; i <= 3; i++) {
- const key = SimpleEnv.get(`BINANCE_API_KEY_${i}`)
- const secret = SimpleEnv.get(`BINANCE_SECRET_KEY_${i}`)
- if (key && secret) {
- accounts.push({
- name: `Binance ${i}`,
- apiKey: key,
- secretKey: secret,
- suffix: `_${i}`,
- })
- }
- }
- return accounts
- }
- /**
- * 发现所有账户
- */
- static discoverAll() {
- return {
- pacifica: this.discoverPacifica(),
- aster: this.discoverAster(),
- binance: this.discoverBinance(),
- }
- }
- }
|