pacifica_test.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import 'dotenv/config'
  2. import { PacificaClient } from '../src/exchanges/pacifica/PacificaClient'
  3. import { PacificaAdapter } from '../src/exchanges/pacifica/PacificaAdapter'
  4. async function main() {
  5. const symbol = process.env.PACIFICA_SYMBOL || 'BTC'
  6. const useAgent = process.env.PACIFICA_USE_AGENT === '1' && !!process.env.PACIFICA_AGENT_PRIVATE_KEY
  7. const client = new PacificaClient({
  8. baseUrl: process.env.PACIFICA_BASE_URL || 'https://api.pacifica.fi',
  9. wsUrl: process.env.PACIFICA_WS_URL || 'wss://ws.pacifica.fi/ws',
  10. apiKey: process.env.PACIFICA_API_KEY,
  11. privateKey: process.env.PACIFICA_ACCOUNT_PRIVATE_KEY || process.env.PACIFICA_PRIVATE_KEY,
  12. account: process.env.PACIFICA_ACCOUNT,
  13. ...(useAgent
  14. ? { agentWallet: process.env.PACIFICA_AGENT_WALLET, agentPrivateKey: process.env.PACIFICA_AGENT_PRIVATE_KEY }
  15. : {}),
  16. })
  17. const ex = new PacificaAdapter(client)
  18. console.log('using account', process.env.PACIFICA_ACCOUNT ? `${process.env.PACIFICA_ACCOUNT.slice(0, 6)}...` : 'N/A')
  19. console.log('=== Pacifica REST smoke ===')
  20. try {
  21. const info = await (client.getPublic as any)(client.endpoints.symbols)
  22. const data = info?.data ?? info
  23. console.log('info sample =', Array.isArray(data) ? data.slice(0, 1) : data)
  24. } catch (e) {
  25. console.error('info() failed', (e as any)?.message || e)
  26. }
  27. try {
  28. const syms = await ex.symbols()
  29. console.log('symbols (sample) =', syms.slice(0, 10))
  30. } catch (e) {
  31. console.error('symbols() failed', (e as any)?.message || e)
  32. }
  33. try {
  34. const bals = await ex.balances()
  35. console.log('balances =', bals)
  36. } catch (e) {
  37. console.error('balances() failed', (e as any)?.message || e)
  38. }
  39. try {
  40. const poss = await ex.positions()
  41. console.log('positions =', poss)
  42. } catch (e) {
  43. console.error('positions() failed', (e as any)?.message || e)
  44. }
  45. try {
  46. const d = await ex.depth(symbol, 20)
  47. console.log('REST depth top =', d.bids[0], d.asks[0])
  48. } catch (e) {
  49. console.error('depth() failed', (e as any)?.message || e)
  50. }
  51. console.log('\n=== Pacifica WS depth (10s) ===')
  52. try {
  53. const ee = ex.ws()
  54. let count = 0
  55. ee.on('depth', (msg: any) => {
  56. if (msg?.symbol !== symbol) return
  57. if (++count <= 5) {
  58. console.log('WS depth update', msg.symbol, msg.bids?.[0], msg.asks?.[0])
  59. }
  60. })
  61. // @ts-ignore subscribeDepth is adapter helper
  62. ;(ex as any).subscribeDepth(symbol)
  63. await new Promise(r => setTimeout(r, 10000))
  64. } catch (e) {
  65. console.error('ws depth failed', (e as any)?.message || e)
  66. }
  67. console.log('\n=== Pacifica openOrders ===')
  68. try {
  69. const oo = await ex.openOrders(symbol)
  70. console.log('openOrders =', oo)
  71. } catch (e) {
  72. console.error('openOrders() failed', (e as any)?.message || e)
  73. }
  74. // 可选:尝试下单(优先市价单,最小化字段,避免内部校验干扰)
  75. if (process.env.PACIFICA_ENABLE_TEST_ORDER === '1') {
  76. try {
  77. const qty = process.env.PACIFICA_TEST_QTY || '0.001'
  78. // 先走市价买单
  79. const mkBuy = await ex.placeOrder({ symbol, side: 'BUY', type: 'MARKET', quantity: qty, tif: 'IOC' })
  80. console.log('placed market buy =', mkBuy)
  81. // 再走市价卖单
  82. const mkSell = await ex.placeOrder({ symbol, side: 'SELL', type: 'MARKET', quantity: qty, tif: 'IOC' })
  83. console.log('placed market sell =', mkSell)
  84. // 补充:最小化限价单用例(GTC),价格偏离,随后撤单
  85. try {
  86. const d = await ex.depth(symbol, 10)
  87. const bestBid = d.bids?.[0]?.price ? Number(d.bids[0].price) : undefined
  88. const bestAsk = d.asks?.[0]?.price ? Number(d.asks[0].price) : undefined
  89. const pxBuy = bestBid ? String(Math.max(1, Math.floor(bestBid - 200))) : '10000'
  90. const pxSell = bestAsk ? String(Math.floor(bestAsk + 200)) : '20000'
  91. const limBuy = await ex.placeOrder({
  92. symbol,
  93. side: 'BUY',
  94. type: 'LIMIT',
  95. quantity: qty,
  96. price: pxBuy,
  97. tif: 'GTC',
  98. })
  99. console.log('placed limit buy (gtc) =', limBuy)
  100. if (limBuy && limBuy.id) {
  101. try {
  102. await ex.cancelOrder(symbol, limBuy.id)
  103. console.log('cancelled limit buy =', limBuy.id)
  104. } catch (e) {
  105. console.error('cancel buy failed', (e as any)?.message || e)
  106. }
  107. }
  108. const limSell = await ex.placeOrder({
  109. symbol,
  110. side: 'SELL',
  111. type: 'LIMIT',
  112. quantity: qty,
  113. price: pxSell,
  114. tif: 'GTC',
  115. })
  116. console.log('placed limit sell (gtc) =', limSell)
  117. if (limSell && limSell.id) {
  118. try {
  119. await ex.cancelOrder(symbol, limSell.id)
  120. console.log('cancelled limit sell =', limSell.id)
  121. } catch (e) {
  122. console.error('cancel sell failed', (e as any)?.message || e)
  123. }
  124. }
  125. } catch (e) {
  126. console.error('limit order failed', (e as any)?.message || e)
  127. }
  128. // 可选:测试止损/止盈(仅在显式开启时运行)
  129. if (process.env.PACIFICA_ENABLE_TEST_STOP === '1') {
  130. try {
  131. const d2 = await ex.depth(symbol, 10)
  132. const ask = d2.asks?.[0]?.price ? Number(d2.asks[0].price) : undefined
  133. const bid = d2.bids?.[0]?.price ? Number(d2.bids[0].price) : undefined
  134. if (ask && bid) {
  135. const tpOnly = await (ex as any).setPositionTp({
  136. symbol,
  137. side: 'SELL',
  138. stopPrice: String(Math.floor(ask * 1.02)),
  139. })
  140. console.log('set TP only =', tpOnly)
  141. const slOnly = await (ex as any).setPositionSl({
  142. symbol,
  143. side: 'SELL',
  144. stopPrice: String(Math.floor(bid * 0.98)),
  145. })
  146. console.log('set SL only =', slOnly)
  147. }
  148. } catch (e) {
  149. console.error('stop/tp test skipped', (e as any)?.message || e)
  150. }
  151. }
  152. // 批量混合用例:Create 两笔 + Cancel 其中一笔
  153. try {
  154. const d3 = await ex.depth(symbol, 10)
  155. const bid3 = d3.bids?.[0]?.price ? Number(d3.bids[0].price) : undefined
  156. const ask3 = d3.asks?.[0]?.price ? Number(d3.asks[0].price) : undefined
  157. if (bid3 && ask3 && (ex as any).batch) {
  158. const pxB = String(Math.max(1, Math.floor(bid3 - 300)))
  159. const pxS = String(Math.floor(ask3 + 300))
  160. const actions: any[] = [
  161. {
  162. type: 'Create',
  163. data: {
  164. account: (ex as any).client.requireAccount(),
  165. symbol,
  166. amount: qty,
  167. side: 'bid',
  168. reduce_only: false,
  169. tif: 'GTC',
  170. price: pxB,
  171. },
  172. },
  173. {
  174. type: 'Create',
  175. data: {
  176. account: (ex as any).client.requireAccount(),
  177. symbol,
  178. amount: qty,
  179. side: 'ask',
  180. reduce_only: false,
  181. tif: 'GTC',
  182. price: pxS,
  183. },
  184. },
  185. ]
  186. const batchRes = await (ex as any).batch(actions)
  187. console.log('batch create result =', batchRes)
  188. // 如果返回有 order_id,则尝试 batch Cancel 第一笔
  189. const createdId = batchRes?.data?.results?.[0]?.order_id || batchRes?.results?.[0]?.order_id
  190. if (createdId) {
  191. const cancelActions = [
  192. { type: 'Cancel', data: { account: (ex as any).client.requireAccount(), symbol, orderId: createdId } },
  193. ]
  194. const batchCancelRes = await (ex as any).batch(cancelActions)
  195. console.log('batch cancel result =', batchCancelRes)
  196. }
  197. }
  198. } catch (e) {
  199. console.error('batch mix failed', (e as any)?.message || e)
  200. }
  201. // 最后执行一次按符号的全撤单
  202. try {
  203. await ex.cancelAll(symbol)
  204. console.log('cancelAll(symbol) done')
  205. } catch (e) {
  206. console.error('cancelAll failed', (e as any)?.message || e)
  207. }
  208. } catch (e) {
  209. console.error('market order failed', (e as any)?.message || e)
  210. }
  211. }
  212. console.log('\nDone.')
  213. }
  214. main().catch(e => {
  215. console.error(e)
  216. process.exitCode = 1
  217. })