输入/搜索内容
内置函数
结构体
内置变量与常量
通用约定
交易所
能力矩阵
中心化交易所
去中心化交易所
预测市场
Polymarket
证券与期货
链上与自定义接入

Polygon链上的预测市场。交易所对象通过Polymarket的CLOB(中央限价订单簿)接口下单、查询订单簿、订单、余额和账户成交,通过Gamma接口查询市场信息,通过data接口查询持仓和市场成交;赎回、合并、拆分经Polymarket的免Gas中继(relayer)提交链上交易。全部是REST轮询,没有行情和订单推送。

名称与配置

exchange.GetName():Futures_Polymarket(预测市场);别名:Futures_Polymarket。

配置项必填说明
存款钱包地址是Polymarket存款钱包(POLY_1271智能合约钱包)地址,即在Polymarket存入资金的钱包地址,必须是合法的0x地址,否则启动失败。订单以它为下单方,持仓和账户成交按它查询;赎回、合并、拆分要求它已在链上部署。
钱包私钥是用于 API 认证和订单签名的私钥。邮箱登录用户请从 reveal.magic.link/polymarket 导出;浏览器钱包用户使用 MetaMask 等钱包私钥(请妥善保管,切勿泄露)
Builder API Key是Polymarket Builder API Key。(详见表下)
Builder API Secret是Polymarket Builder API Secret,与BuilderKey、BuilderPassphrase一起用于relayer认证。
Builder API Passphrase是Polymarket Builder API Passphrase,与BuilderKey、BuilderSecret一起用于relayer认证。

表中长说明的其余部分:

  • Builder API Key:与BuilderSecret、BuilderPassphrase三项都必须填写(缺一项启动时报错),用于赎回、合并、拆分时向relayer认证;下单用的CLOB接口凭据由私钥自动派生,不用这三项。

交易对与合约代码

交易对示例:will-btc-100k_USDC

交易对为市场(market)的标识(slug)加_USDC,计价币只能是USDC。slug区分大小写,exchange.SetCurrency()按原样保存、不转大写。注意是市场的slug而不是事件(event)的slug:一个多选项事件(例如「谁会赢得选举」)下的每个候选都是一个独立的二元市场,各有自己的slug。

合约代码说明
Yes结果选项「Yes」,大多数市场的两个选项是Yes、No。
No结果选项「No」。
Up涨跌类市场(如加密货币短周期涨跌)的结果选项,另一个是Down。
Down涨跌类市场的结果选项。

预测市场没有永续、交割之分,也没有默认合约:合约代码就是市场的结果选项名称,每个市场恰好两个选项(体育等市场的选项可能是队名)。选项名中的空格换成-(例如选项「Donald Trump」写作Donald-Trump),完整品种代码形如will-btc-100k_USDC.Yes。选项名本身含-或.也照写(例如选项「Non-Fed」写作Non-Fed、「U.S. Fed」写作U.S.-Fed)。下单、行情按选项名不区分大小写匹配,但exchange.GetPositions()按品种代码精确比较、赎回按持仓的品种代码匹配,所以请照搬exchange.GetMarkets()、exchange.GetPositions()返回的写法。

exchange.SetContractType()只检查形式(不能为空、不能含空白和.),swap等写法不会当场报错,而是在之后的调用中报「outcome not found」。

获取品种代码:exchange.GetMarkets()每个选项一行,键就是完整品种代码;也可以用exchange.IO("gamma", "/markets/slug/<市场slug>")查询某个市场的outcomes,或用exchange.IO("gamma", "/events/slug/<事件slug>")列出一个事件下的各个市场。

exchange.GetMarkets()里每行的Symbol(交易所原生代码)是该选项的CLOB token ID,只用于对照交易所接口,不能当作合约代码使用。

专属IO指令
指令参数说明返回值
proxyWalletAddress—获取配置的存款钱包地址(EIP-55校验和格式)。地址字符串。
redeemsymbol[, wait]市场结算后,把存款钱包持有的该市场份额赎回成USDC(两个选项一起赎回,经relayer免Gas)。(详见表下)wait为true时返回relayer确认后的交易记录对象(state为STATE_CONFIRMED);为false时立即返回{"transactionID": "..."},不等确认、不刷新余额缓存。(详见表下)
mergesymbol[, amount[, wait]]把等量的两个选项份额合并回USDC(经relayer免Gas)。(详见表下)同redeem。
splitsymbol, amount[, wait]把USDC拆分成等量的两个选项份额(经relayer免Gas)。(详见表下)同redeem。
batchOrdersorders批量下单,orders为1~15个订单对象的数组,全部签名后一次提交,不写交易日志。(详见表下)交易所原始应答数组,与orders逐项对应:成功的项带orderID,被拒的项带errorMsg。部分订单被拒时照常返回该数组,被拒的每一项另报一条错误日志;全部被拒或应答格式异常时报错并返回空值。
markets_cursor[string]查询或设置exchange.GetMarkets()的分页游标(传空串清除,回到第一页);传next把游标推进到下一页,用法见注意事项。当前(设置或推进后)的游标字符串;推进到最后一页之后为空串。当前游标还没有取过页时传next报错。
tickers_cursor[string]同markets_cursor,作用于exchange.GetTickers(),两个游标相互独立。同markets_cursor。
base[url] / kind, url不传参数返回当前CLOB接口地址;传一个URL时切换CLOB地址(下单、订单、余额、账户成交、订单簿都走它),exchange.GetBase()、exchange.SetBase()即此形式。(详见表下)无参、一参时返回地址字符串(当前地址或修改前的地址);kind, url形式返回空值。
apimethod, path[, params[, raw]]向CLOB发请求,默认带L2签名:GET的params拼成查询串,其它方法作为JSON请求体;path可以写完整URL(例如data接口地址);raw为JSON对象(或JSON对象字符串)时并入params,为其它字符串时作为原样的查询串或请求体,传false时不签名。交易所原始应答(JSON自动解析);请求失败报错并返回空值。
gammapath向Gamma接口(市场信息)发不签名的GET请求,path含查询串,例如exchange.IO("gamma", "/markets/slug/will-btc-100k");地址跟随exchange.IO("base", "gamma", url)。(详见表下)交易所原始应答(JSON自动解析);请求失败返回空值。
clobpath向CLOB接口发不签名的GET请求,例如exchange.IO("clob", "/book?token_id=...");需要签名的私有接口用exchange.IO("api", ...)。交易所原始应答(JSON自动解析);请求失败返回空值。
datapath向data接口(持仓、市场成交)发不签名的GET请求,例如exchange.IO("data", "/trades?market=<conditionId>");地址跟随exchange.IO("base", "data", url)。交易所原始应答(JSON自动解析);请求失败返回空值。

表中长说明的其余部分:

  • redeem:symbol须与exchange.GetPositions()中一个可赎回(持仓原始数据的redeemable为true)且份额大于0的持仓的品种代码完全一致;存款钱包须已在链上部署。wait默认true:每2秒查询一次relayer,最多约2分钟,确认后刷新CLOB的余额缓存。也可以传对象{symbol, wait}。
  • redeem的返回值:relayer报告交易失败(STATE_FAILED、STATE_INVALID)、等待超时或刷新缓存失败时报错,错误信息带transactionID;后两种情况交易已经提交(超时的交易之后仍可能上链),重试前先用exchange.GetPositions()、exchange.GetAccount()核对。等待超时后,同一市场的同一操作在该交易确认或失败之前再次调用会直接报错、不重复提交。
  • merge:symbol取该市场任一选项的品种代码;amount为份额数(截断到6位小数),为0或不传时自动取两个选项持仓中较小的一个。wait同redeem。也可以传对象{symbol, amount, wait}。
  • split:symbol取该市场任一选项的品种代码;amount为USDC数量,必须大于0(截断到6位小数),拆出两个选项各amount份。wait同redeem。也可以传对象{symbol, amount, wait}。
  • batchOrders:每个对象:symbol(完整品种代码)、side(buy/sell)、price(小于等于0为市价单)、amount(份额),可选option对象,键与下单参数相同(orderType、expiration、postOnly、deferExec、slippage,见注意事项)。
  • base:exchange.IO("base", kind, url)切换各服务的地址,kind只能是gamma(市场信息、市场列表)、data(持仓、市场成交)、relayer(赎回、合并、拆分)或clob(同一参形式,切换CLOB地址)。一参形式只接受http://、https://开头的地址,其它值报错。
  • gamma:也可以把指令名写成完整的服务地址、第二个参数写路径,例如exchange.IO("https://gamma-api.polymarket.com", "/markets/slug/will-btc-100k")。

通用指令currency见exchange.IO。

常用用法
用Gamma接口找到市场,读取盘口与最近成交
javascript
function main() { // 进行中、24小时成交额最大的市场(/markets按市场列出,/events按事件列出) var path = "/markets?limit=1&closed=false&order=volume24hr&ascending=false" var list = exchange.IO("gamma", path) var m = exchange.IO("gamma", "/markets/slug/" + list[0].slug) // outcomes、clobTokenIds在Gamma应答中是JSON字符串 var outcomes = JSON.parse(m.outcomes) var tokenIds = JSON.parse(m.clobTokenIds) // 品种代码:市场slug加_USDC.再加选项名(空格换成-) var symbol = m.slug + "_USDC." + outcomes[0].replace(/ /g, "-") Log("品种:", symbol, "价格步长:", m.orderPriceMinTickSize, "最小数量:", m.orderMinSize) var depth = exchange.GetDepth(symbol) Log("买一:", depth.Bids[0], "卖一:", depth.Asks[0]) // 同一选项的原始订单簿:CLOB的/book接口按token ID查询 var book = exchange.IO("clob", "/book?token_id=" + tokenIds[0]) Log("原始订单簿 tick_size:", book.tick_size, "买盘档数:", book.bids.length) // 市场最近成交:data接口按conditionId查询 var trades = exchange.IO("data", "/trades?market=" + m.conditionId + "&limit=5") for (var i = 0; i < trades.length; i++) { Log(trades[i].outcome, trades[i].side, trades[i].price, trades[i].size) } }
用markets_cursor逐页读取市场列表
javascript
function main() { exchange.IO("markets_cursor", "") // 回到第一页 var all = {} for (var page = 1; page <= 5; page++) { // 每次返回当前游标处的一页(约100个市场,每个选项一行),不移动游标 var markets = exchange.GetMarkets() for (var k in markets) { all[k] = markets[k] } Log("第", page, "页:", Object.keys(markets).length, "个品种") // 推进到下一页;最后一页之后返回空串 if (exchange.IO("markets_cursor", "next") === "") { break } } Log("共", Object.keys(all).length, "个品种") }
查询存款钱包的持仓原始数据与挂单
javascript
function main() { var wallet = exchange.IO("proxyWalletAddress") // data接口:持仓原始数据(含redeemable、conditionId等字段) var rows = exchange.IO("data", "/positions?user=" + wallet + "&sizeThreshold=0") Log("持仓行数:", rows.length) // CLOB私有接口:默认带L2签名 var r = exchange.IO("api", "GET", "/data/orders") Log("挂单数:", r.count, "本页:", r.data.length) }
拆分与合并:USDC换成两个选项的份额,再换回USDC
javascript
function main() { var symbol = "will-btc-100k_USDC.Yes" // 该市场任一选项的品种代码 // 用10 USDC拆出Yes、No各10份,等待relayer确认 var r = exchange.IO("split", symbol, 10) Log("拆分:", r ? r.state : GetLastError()) // 合并:不传数量时取两个选项持仓中较小的一个 r = exchange.IO("merge", symbol) Log("合并:", r ? r.state : GetLastError()) // 不等确认:立即返回transactionID r = exchange.IO("split", {symbol: symbol, amount: 5, wait: false}) Log("已提交:", r ? r.transactionID : GetLastError()) }
赎回所有已结算的持仓
javascript
function main() { var done = {} var positions = exchange.GetPositions() for (var i = 0; i < positions.length; i++) { var p = positions[i] var slug = p.Symbol.split("_USDC.")[0] // Info.redeemable为true表示市场已结算;同一市场的两个选项一起赎回,只调用一次 if (!p.Info.redeemable || p.Amount <= 0 || done[slug]) { continue } var r = exchange.IO("redeem", p.Symbol) Log("赎回", p.Symbol, r ? r.state : GetLastError()) done[slug] = true } }
用batchOrders一次提交多个订单
javascript
function main() { var r = exchange.IO("batchOrders", [ {symbol: "will-btc-100k_USDC.Yes", side: "buy", price: 0.3, amount: 10}, {symbol: "will-btc-100k_USDC.No", side: "buy", price: 0.6, amount: 10, option: {postOnly: true}} ]) // 应答与订单逐项对应:成功的带orderID,被拒的带errorMsg;全部被拒时返回空值 for (var i = 0; r && i < r.length; i++) { Log(i, r[i].errorMsg ? "被拒: " + r[i].errorMsg : "orderID: " + r[i].orderID) } }

函数支持差异

不支持(调用时报错并返回空值):exchange.ModifyOrder、exchange.SetMarginLevel、exchange.GetFundings、exchange.CreateConditionOrder、exchange.ModifyConditionOrder、exchange.CancelConditionOrder、exchange.GetConditionOrder、exchange.GetConditionOrders、exchange.GetHistoryConditionOrders。

以回退方式支持:

  • exchange.GetRecords:交易所没有K线接口,由托管者用成交记录合成:首次调用只有最近成交覆盖的少量K线,随调用逐步累积。

保证金、账户与模拟盘

保证金模式:没有保证金和杠杆:买入份额用USDC全额支付,exchange.IO("cross", ...)等保证金指令报错。

持仓模式:持仓只有多头:每个选项的份额是一个持仓(Type为多头),看空某个选项就买入另一个选项。Price为持仓均价,Profit为交易所给出的盈亏(cashPnl),Margin为持仓当前市值;持仓原始数据中redeemable为true表示市场已结算、可以用redeem赎回。没有平仓方向:用exchange.SetDirection()设为closebuy或closesell后下单、或下单方向写closebuy/closesell都会被拒绝,卖出就是卖出持有的份额。

账户:资金和持仓都在存款钱包(配置项ProxyWalletAddress)里,订单的下单方和签名方都是存款钱包,由私钥按POLY_1271(签名类型3)签名。exchange.GetAccount()的Balance为CLOB报告的可用USDC,Equity为Balance加全部持仓市值,UPnL为各持仓cashPnl之和,FrozenBalance恒为0。

模拟盘:没有模拟盘,所有调用都在Polygon主网上使用真实资金。

注意事项
  • 价格是每份的USDC价格,在0~1之间,按市场的价格步长(exchange.GetMarkets()的TickSize,0.1/0.01/0.001/0.0001)截断,大于1时按1减一个步长下单。数量单位是份额,截断到2位小数;最小下单量见MinQty(常见为5份),不预先检查,由交易所拒单。
  • 市价单(价格传-1,或在下单参数中写明type: "market",此时忽略价格):CLOB只有限价单,连接器沿对手盘累计到下单量所在档位(深度不够取最后一档),以该档价格×(1±滑点)作为限价发出,滑点默认0.01,对手盘为空时报错;买卖的数量都是份额。这样下出的仍是GTC订单,未成交部分会留在盘口;需要立即成交否则撤销时,在最后一个参数传{tif: "ioc"}(FAK)或{tif: "fok"},例如exchange.CreateOrder(symbol, "buy", -1, 10, {tif: "ioc"})。
  • 其它下单参数放在最后一个对象参数里,例如exchange.CreateOrder(symbol, "buy", price, amount, {orderType: "GTD", expiration: 1830000000})(也兼容旧写法"buy;{\"orderType\":\"GTD\"}"、"buy;slippage=0.02"):orderType(GTC默认、GTD、FOK、FAK)、expiration(GTD必填,Unix秒,须晚于当前60秒以上;非GTD订单传入会报错)、postOnly(仅GTC/GTD)、deferExec(原样传给交易所)、slippage(市价单滑点)。
  • exchange.GetOrders()、exchange.GetPositions()不传品种时返回全部市场;exchange.GetHistoryOrders()不传品种时只查当前品种,传空串查全部。
  • exchange.GetHistoryOrders()由账户成交记录生成:每笔成交一行(状态为已成交,同一订单多次成交会出现多行),已撤销或从未成交的订单不会出现;since可传毫秒或秒,不传limit时最多300条。
  • exchange.GetTicker()取该选项自己的订单簿和最新成交价,High、Low就是当前卖一、买一价(没有24小时高低价),Volume是整个市场(两个选项合计)的24小时成交额。exchange.GetTickers()取自Gamma市场列表,第二个选项的价格由第一个选项按1 - x换算。
  • exchange.GetMarkets()、exchange.GetTickers()每次只返回一页(约100个市场)。游标为空时只返回Gamma市场列表的第一页;调用返回当前游标处的一页,不移动游标(exchange.SetContractType()等内部查询也不会推进它);取过一页后用exchange.IO("markets_cursor", "next")(或tickers_cursor)推进到下一页,最后一页之后游标回到空串。逐页翻:exchange.IO("markets_cursor", ""),然后循环调用exchange.GetMarkets()与exchange.IO("markets_cursor", "next")直到返回空串。也可以直接设置游标,例如Gamma接口/markets/keyset应答中的next_cursor。