//npm install @polymarket/clob-client //npm install ethers //npm install dotenv import { ClobClient, OrderType, Side, } from '@polymarket/clob-client' import { Wallet } from '@ethersproject/wallet' import dotenv from 'dotenv' // 加载环境变量 (.env.local 优先) dotenv.config({ path: '.env.local' }) // 必填校验 if (!process.env.PRIVATE_KEY) { console.error('错误: 请在 .env.local 文件中设置 PRIVATE_KEY') process.exit(1) } if (!process.env.FUNDER_ADDRESS) { console.error('错误: 请在 .env.local 文件中设置 FUNDER_ADDRESS') process.exit(1) } const host = 'https://clob.polymarket.com' const funder = process.env.FUNDER_ADDRESS const signer = new Wallet(process.env.PRIVATE_KEY) // 从环境变量读取默认下单参数 const signatureType = parseInt(process.env.SIGNATURE_TYPE) || 1 const orderPrice = parseFloat(process.env.ORDER_PRICE) || 0.49 const orderSize = parseInt(process.env.ORDER_SIZE) || 5 function getSlug() { const now = new Date() const utcTimestamp = Math.floor(now.getTime() / 1000) const intervalSeconds = 15 * 60 const nextInterval = Math.ceil(utcTimestamp / intervalSeconds) * intervalSeconds const slug = `btc-updown-15m-${nextInterval}` console.log('当前时间:', now.toISOString()) console.log('当前 UTC 时间戳:', utcTimestamp) console.log('下一个 15 分钟间隔时间戳:', nextInterval) console.log('生成的 slug:', slug) return slug } async function getTokenIdsBySlug() { const slug = getSlug() console.log('正在获取市场信息,slug:', slug) const response = await fetch(`https://gamma-api.polymarket.com/markets?slug=${slug}`) if (!response.ok) { throw new Error(`HTTP 错误: ${response.status} ${response.statusText}`) } const data = await response.json() if (!data || data.length === 0) { throw new Error(`未找到 slug 为 ${slug} 的市场`) } if (!data[0].clobTokenIds) { throw new Error('市场数据中缺少 clobTokenIds 字段') } const clobTokenIds = JSON.parse(data[0].clobTokenIds) console.log('市场信息:', data[0].question) console.log('UP tokenID:', clobTokenIds[0]) console.log('DOWN tokenID:', clobTokenIds[1]) return { upTokenID: clobTokenIds[0], downTokenID: clobTokenIds[1] } } function parseDirectionArg() { const arg = (process.argv[2] || '').toLowerCase() if (arg !== 'up' && arg !== 'down') { console.error('用法: node bid.mjs [price] [size]') console.error('示例: node bid.mjs up 0.49 5') process.exit(1) } const priceArg = process.argv[3] const sizeArg = process.argv[4] const price = priceArg ? parseFloat(priceArg) : orderPrice const size = sizeArg ? parseInt(sizeArg) : orderSize if (Number.isNaN(price) || Number.isNaN(size)) { console.error('价格或数量无效。示例: node bid.mjs up 0.49 5') process.exit(1) } return { direction: arg, price, size } } async function main() { try { const { direction, price, size } = parseDirectionArg() console.log('配置信息:') console.log('- 下单方向:', direction.toUpperCase()) console.log('- 订单价格:', price) console.log('- 订单数量:', size) console.log('- 签名类型:', signatureType) console.log('- 地址:', funder) console.log('正在初始化 CLOB 客户端...') const creds = await new ClobClient(host, 137, signer).createOrDeriveApiKey() const clobClient = new ClobClient( host, 137, signer, creds, signatureType, funder ) console.log('正在获取市场 tokenID...') const { upTokenID, downTokenID } = await getTokenIdsBySlug() const tokenID = direction === 'up' ? upTokenID : downTokenID console.log(`创建 ${direction.toUpperCase()} 限价单...`) const result = await clobClient.createAndPostOrder( { tokenID, price, side: Side.BUY, size, feeRateBps: 0, }, { tickSize: '0.01', negRisk: false, }, OrderType.GTC ) if (result?.success) { console.log(`${direction.toUpperCase()} 订单成功:`, result) } else { console.log(`${direction.toUpperCase()} 订单返回:`, result) } } catch (error) { console.error('下单失败:', error.message) console.error('完整错误信息:', error) process.exit(1) } } // 执行 main()