| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- 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
- })
|