bid.mjs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //npm install @polymarket/clob-client
  2. //npm install ethers
  3. //npm install dotenv
  4. import {
  5. ClobClient,
  6. OrderType,
  7. Side,
  8. } from '@polymarket/clob-client'
  9. import { Wallet } from '@ethersproject/wallet'
  10. import dotenv from 'dotenv'
  11. // 加载环境变量 (.env.local 优先)
  12. dotenv.config({ path: '.env.local' })
  13. // 必填校验
  14. if (!process.env.PRIVATE_KEY) {
  15. console.error('错误: 请在 .env.local 文件中设置 PRIVATE_KEY')
  16. process.exit(1)
  17. }
  18. if (!process.env.FUNDER_ADDRESS) {
  19. console.error('错误: 请在 .env.local 文件中设置 FUNDER_ADDRESS')
  20. process.exit(1)
  21. }
  22. const host = 'https://clob.polymarket.com'
  23. const funder = process.env.FUNDER_ADDRESS
  24. const signer = new Wallet(process.env.PRIVATE_KEY)
  25. // 从环境变量读取默认下单参数
  26. const signatureType = parseInt(process.env.SIGNATURE_TYPE) || 1
  27. const orderPrice = parseFloat(process.env.ORDER_PRICE) || 0.49
  28. const orderSize = parseInt(process.env.ORDER_SIZE) || 5
  29. function getSlug() {
  30. const now = new Date()
  31. const utcTimestamp = Math.floor(now.getTime() / 1000)
  32. const intervalSeconds = 15 * 60
  33. const nextInterval = Math.ceil(utcTimestamp / intervalSeconds) * intervalSeconds
  34. const slug = `btc-updown-15m-${nextInterval}`
  35. console.log('当前时间:', now.toISOString())
  36. console.log('当前 UTC 时间戳:', utcTimestamp)
  37. console.log('下一个 15 分钟间隔时间戳:', nextInterval)
  38. console.log('生成的 slug:', slug)
  39. return slug
  40. }
  41. async function getTokenIdsBySlug() {
  42. const slug = getSlug()
  43. console.log('正在获取市场信息,slug:', slug)
  44. const response = await fetch(`https://gamma-api.polymarket.com/markets?slug=${slug}`)
  45. if (!response.ok) {
  46. throw new Error(`HTTP 错误: ${response.status} ${response.statusText}`)
  47. }
  48. const data = await response.json()
  49. if (!data || data.length === 0) {
  50. throw new Error(`未找到 slug 为 ${slug} 的市场`)
  51. }
  52. if (!data[0].clobTokenIds) {
  53. throw new Error('市场数据中缺少 clobTokenIds 字段')
  54. }
  55. const clobTokenIds = JSON.parse(data[0].clobTokenIds)
  56. console.log('市场信息:', data[0].question)
  57. console.log('UP tokenID:', clobTokenIds[0])
  58. console.log('DOWN tokenID:', clobTokenIds[1])
  59. return { upTokenID: clobTokenIds[0], downTokenID: clobTokenIds[1] }
  60. }
  61. function parseDirectionArg() {
  62. const arg = (process.argv[2] || '').toLowerCase()
  63. if (arg !== 'up' && arg !== 'down') {
  64. console.error('用法: node bid.mjs <up|down> [price] [size]')
  65. console.error('示例: node bid.mjs up 0.49 5')
  66. process.exit(1)
  67. }
  68. const priceArg = process.argv[3]
  69. const sizeArg = process.argv[4]
  70. const price = priceArg ? parseFloat(priceArg) : orderPrice
  71. const size = sizeArg ? parseInt(sizeArg) : orderSize
  72. if (Number.isNaN(price) || Number.isNaN(size)) {
  73. console.error('价格或数量无效。示例: node bid.mjs up 0.49 5')
  74. process.exit(1)
  75. }
  76. return { direction: arg, price, size }
  77. }
  78. async function main() {
  79. try {
  80. const { direction, price, size } = parseDirectionArg()
  81. console.log('配置信息:')
  82. console.log('- 下单方向:', direction.toUpperCase())
  83. console.log('- 订单价格:', price)
  84. console.log('- 订单数量:', size)
  85. console.log('- 签名类型:', signatureType)
  86. console.log('- 地址:', funder)
  87. console.log('正在初始化 CLOB 客户端...')
  88. const creds = await new ClobClient(host, 137, signer).createOrDeriveApiKey()
  89. const clobClient = new ClobClient(
  90. host,
  91. 137,
  92. signer,
  93. creds,
  94. signatureType,
  95. funder
  96. )
  97. console.log('正在获取市场 tokenID...')
  98. const { upTokenID, downTokenID } = await getTokenIdsBySlug()
  99. const tokenID = direction === 'up' ? upTokenID : downTokenID
  100. console.log(`创建 ${direction.toUpperCase()} 限价单...`)
  101. const result = await clobClient.createAndPostOrder(
  102. {
  103. tokenID,
  104. price,
  105. side: Side.BUY,
  106. size,
  107. feeRateBps: 0,
  108. },
  109. {
  110. tickSize: '0.01',
  111. negRisk: false,
  112. },
  113. OrderType.GTC
  114. )
  115. if (result?.success) {
  116. console.log(`${direction.toUpperCase()} 订单成功:`, result)
  117. } else {
  118. console.log(`${direction.toUpperCase()} 订单返回:`, result)
  119. }
  120. } catch (error) {
  121. console.error('下单失败:', error.message)
  122. console.error('完整错误信息:', error)
  123. process.exit(1)
  124. }
  125. }
  126. // 执行
  127. main()