import 'dotenv/config' import { PacificaClient } from '../src/exchanges/pacifica/PacificaClient' import { PacificaAdapter } from '../src/exchanges/pacifica/PacificaAdapter' async function main() { const symbol = process.env.PACIFICA_SYMBOL || 'BTC' const useAgent = process.env.PACIFICA_USE_AGENT === '1' && !!process.env.PACIFICA_AGENT_PRIVATE_KEY const client = new PacificaClient({ baseUrl: process.env.PACIFICA_BASE_URL || 'https://api.pacifica.fi', wsUrl: process.env.PACIFICA_WS_URL || 'wss://ws.pacifica.fi/ws', apiKey: process.env.PACIFICA_API_KEY, privateKey: process.env.PACIFICA_ACCOUNT_PRIVATE_KEY || process.env.PACIFICA_PRIVATE_KEY, account: process.env.PACIFICA_ACCOUNT, ...(useAgent ? { agentWallet: process.env.PACIFICA_AGENT_WALLET, agentPrivateKey: process.env.PACIFICA_AGENT_PRIVATE_KEY } : {}), }) const ex = new PacificaAdapter(client) console.log('using account', process.env.PACIFICA_ACCOUNT ? `${process.env.PACIFICA_ACCOUNT.slice(0, 6)}...` : 'N/A') console.log('=== Pacifica REST smoke ===') try { const info = await (client.getPublic as any)(client.endpoints.symbols) const data = info?.data ?? info console.log('info sample =', Array.isArray(data) ? data.slice(0, 1) : data) } catch (e) { console.error('info() failed', (e as any)?.message || e) } try { const syms = await ex.symbols() console.log('symbols (sample) =', syms.slice(0, 10)) } catch (e) { console.error('symbols() failed', (e as any)?.message || e) } try { const bals = await ex.balances() console.log('balances =', bals) } catch (e) { console.error('balances() failed', (e as any)?.message || e) } try { const poss = await ex.positions() console.log('positions =', poss) } catch (e) { console.error('positions() failed', (e as any)?.message || e) } try { const d = await ex.depth(symbol, 20) console.log('REST depth top =', d.bids[0], d.asks[0]) } catch (e) { console.error('depth() failed', (e as any)?.message || e) } console.log('\n=== Pacifica WS depth (10s) ===') try { const ee = ex.ws() let count = 0 ee.on('depth', (msg: any) => { if (msg?.symbol !== symbol) return if (++count <= 5) { console.log('WS depth update', msg.symbol, msg.bids?.[0], msg.asks?.[0]) } }) // @ts-ignore subscribeDepth is adapter helper ;(ex as any).subscribeDepth(symbol) await new Promise(r => setTimeout(r, 10000)) } catch (e) { console.error('ws depth failed', (e as any)?.message || e) } console.log('\n=== Pacifica openOrders ===') try { const oo = await ex.openOrders(symbol) console.log('openOrders =', oo) } catch (e) { console.error('openOrders() failed', (e as any)?.message || e) } // 可选:尝试下单(优先市价单,最小化字段,避免内部校验干扰) if (process.env.PACIFICA_ENABLE_TEST_ORDER === '1') { try { const qty = process.env.PACIFICA_TEST_QTY || '0.001' // 先走市价买单 const mkBuy = await ex.placeOrder({ symbol, side: 'BUY', type: 'MARKET', quantity: qty, tif: 'IOC' }) console.log('placed market buy =', mkBuy) // 再走市价卖单 const mkSell = await ex.placeOrder({ symbol, side: 'SELL', type: 'MARKET', quantity: qty, tif: 'IOC' }) console.log('placed market sell =', mkSell) // 补充:最小化限价单用例(GTC),价格偏离,随后撤单 try { const d = await ex.depth(symbol, 10) const bestBid = d.bids?.[0]?.price ? Number(d.bids[0].price) : undefined const bestAsk = d.asks?.[0]?.price ? Number(d.asks[0].price) : undefined const pxBuy = bestBid ? String(Math.max(1, Math.floor(bestBid - 200))) : '10000' const pxSell = bestAsk ? String(Math.floor(bestAsk + 200)) : '20000' const limBuy = await ex.placeOrder({ symbol, side: 'BUY', type: 'LIMIT', quantity: qty, price: pxBuy, tif: 'GTC', }) console.log('placed limit buy (gtc) =', limBuy) if (limBuy && limBuy.id) { try { await ex.cancelOrder(symbol, limBuy.id) console.log('cancelled limit buy =', limBuy.id) } catch (e) { console.error('cancel buy failed', (e as any)?.message || e) } } const limSell = await ex.placeOrder({ symbol, side: 'SELL', type: 'LIMIT', quantity: qty, price: pxSell, tif: 'GTC', }) console.log('placed limit sell (gtc) =', limSell) if (limSell && limSell.id) { try { await ex.cancelOrder(symbol, limSell.id) console.log('cancelled limit sell =', limSell.id) } catch (e) { console.error('cancel sell failed', (e as any)?.message || e) } } } catch (e) { console.error('limit order failed', (e as any)?.message || e) } // 可选:测试止损/止盈(仅在显式开启时运行) if (process.env.PACIFICA_ENABLE_TEST_STOP === '1') { try { const d2 = await ex.depth(symbol, 10) const ask = d2.asks?.[0]?.price ? Number(d2.asks[0].price) : undefined const bid = d2.bids?.[0]?.price ? Number(d2.bids[0].price) : undefined if (ask && bid) { const tpOnly = await (ex as any).setPositionTp({ symbol, side: 'SELL', stopPrice: String(Math.floor(ask * 1.02)), }) console.log('set TP only =', tpOnly) const slOnly = await (ex as any).setPositionSl({ symbol, side: 'SELL', stopPrice: String(Math.floor(bid * 0.98)), }) console.log('set SL only =', slOnly) } } catch (e) { console.error('stop/tp test skipped', (e as any)?.message || e) } } // 批量混合用例:Create 两笔 + Cancel 其中一笔 try { const d3 = await ex.depth(symbol, 10) const bid3 = d3.bids?.[0]?.price ? Number(d3.bids[0].price) : undefined const ask3 = d3.asks?.[0]?.price ? Number(d3.asks[0].price) : undefined if (bid3 && ask3 && (ex as any).batch) { const pxB = String(Math.max(1, Math.floor(bid3 - 300))) const pxS = String(Math.floor(ask3 + 300)) const actions: any[] = [ { type: 'Create', data: { account: (ex as any).client.requireAccount(), symbol, amount: qty, side: 'bid', reduce_only: false, tif: 'GTC', price: pxB, }, }, { type: 'Create', data: { account: (ex as any).client.requireAccount(), symbol, amount: qty, side: 'ask', reduce_only: false, tif: 'GTC', price: pxS, }, }, ] const batchRes = await (ex as any).batch(actions) console.log('batch create result =', batchRes) // 如果返回有 order_id,则尝试 batch Cancel 第一笔 const createdId = batchRes?.data?.results?.[0]?.order_id || batchRes?.results?.[0]?.order_id if (createdId) { const cancelActions = [ { type: 'Cancel', data: { account: (ex as any).client.requireAccount(), symbol, orderId: createdId } }, ] const batchCancelRes = await (ex as any).batch(cancelActions) console.log('batch cancel result =', batchCancelRes) } } } catch (e) { console.error('batch mix failed', (e as any)?.message || e) } // 最后执行一次按符号的全撤单 try { await ex.cancelAll(symbol) console.log('cancelAll(symbol) done') } catch (e) { console.error('cancelAll failed', (e as any)?.message || e) } } catch (e) { console.error('market order failed', (e as any)?.message || e) } } console.log('\nDone.') } main().catch(e => { console.error(e) process.exitCode = 1 })