import 'dotenv/config' import { AsterAdapter } from '../src/exchanges/aster/asterAdapter' import { AsterWsClient } from '../src/exchanges/aster/wsClient' async function main() { const httpBase = process.env.ASTER_HTTP_BASE || 'https://fapi.asterdex.com' const wsBase = process.env.ASTER_WS_BASE || 'wss://fstream.asterdex.com' const user = process.env.ASTER_ORDER_USER || '' const signer = process.env.ASTER_API_KEY || '' const pk = process.env.ASTER_API_SECRET || '' console.log('Env check:', { ASTER_ORDER_USER: user ? 'SET' : 'NOT_SET', ASTER_API_KEY: signer ? 'SET' : 'NOT_SET', ASTER_API_SECRET: pk ? 'SET' : 'NOT_SET', }) if (!user || !signer || !pk) { console.error('Missing envs: require ASTER_ORDER_USER / ASTER_API_KEY / ASTER_API_SECRET') process.exit(1) } const adapter = new AsterAdapter({ rpcUrl: '', chainId: 0, routerAddress: '', httpBase, defaultUser: user, defaultSigner: signer, }) // 1) 获取 listenKey const ensured = await adapter.ensureListenKey() const listenKey = ensured.listenKey console.log('listenKey:', listenKey) // 2) 连接账户 user stream const client = new AsterWsClient({ wsUrl: wsBase }) client.setUserStream(listenKey, wsBase) client.on('open', () => console.log('[WS] connected')) client.on('close', (c, r) => console.log('[WS] closed', c, r)) client.on('error', e => console.log('[WS] error', e)) client.on('ws_error', e => console.log('[WS] ws_error', e)) // 原始与标准化事件 client.on('raw', m => console.log('[WS] raw', JSON.stringify(m))) client.on('balance', p => console.log('[WS] balance', JSON.stringify(p))) client.on('account_positions', p => console.log('[WS] positions', JSON.stringify(p))) client.on('account_info', p => console.log('[WS] account_info', JSON.stringify(p))) client.on('orders', p => console.log('[WS] orders', JSON.stringify(p))) client.connectUserStream() // 可选:自动触发一笔很小的下单来验证账户事件(设置 ASTER_WS_TRIGGER_ORDER=1 生效) if (process.env.ASTER_WS_TRIGGER_ORDER === '1') { try { const symbol = process.env.ASTER_TEST_SYMBOL || 'BTCUSDT' const url = `${httpBase.replace(/\/$/, '')}/fapi/v3/order` // 给 WS 一点时间完成握手 await new Promise(r => setTimeout(r, 1500)) async function postOrder(formFields: Record) { return await fetch(url, { method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' } as any, body: new URLSearchParams(formFields as any).toString(), } as any) } async function tryOpenClose(positionSide: 'BOTH' | 'LONG' | 'SHORT') { const qty = process.env.ASTER_TEST_QTY || '0.001' const openSide = 'BUY' const closeSide = 'SELL' const openSig = await adapter.generateOrderSignature( { symbol, positionSide, type: 'MARKET', side: openSide, quantity: qty, timeInForce: undefined, }, { user, signer, privateKey: pk }, ) const res1 = await postOrder(openSig.formFields) const txt1 = await res1.text() console.log(`[TRIGGER ${positionSide}] open`, res1.status, txt1) // 若开仓失败,直接返回 false 以便上层 fallback if (!res1.ok) return false // 给 WS 一点时间推送 await new Promise(r => setTimeout(r, 1000)) const closeSig = await adapter.generateOrderSignature( { symbol, positionSide, type: 'MARKET', side: closeSide, quantity: qty, timeInForce: undefined, // 对于 LONG/SHORT 情况,SELL 将会减仓 }, { user, signer, privateKey: pk }, ) const res2 = await postOrder(closeSig.formFields) const txt2 = await res2.text() console.log(`[TRIGGER ${positionSide}] close`, res2.status, txt2) return res2.ok } // 顺序尝试:BOTH -> LONG -> SHORT const okBoth = await tryOpenClose('BOTH') if (!okBoth) { const okLong = await tryOpenClose('LONG') if (!okLong) { await tryOpenClose('SHORT') } } } catch (e) { console.log('[TRIGGER] error', (e as any)?.message || e) } } // 保持 60 秒观察 setTimeout(() => { console.log('Done.') process.exit(0) }, 60000) } main().catch(e => { console.error(e) process.exit(1) })