Documentation Index
Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt
Use this file to discover all available pages before exploring further.
概述
在 Polymarket CLOB 上交易
Polymarket 的 CLOB (Central Limit Order Book) 是一个混合去中心化交易系统------链下订单撮合与链上结算通过 Exchange 合约实现(由 Chainsecurity 审计)。所有交易均为非托管式。订单是 EIP-712 签名消息,撮合后的交易在 Polygon 上原子化结算。运营方无法设定价格或执行未授权交易。
我们建议使用开源 SDK 客户端,它们可以处理订单签名、身份验证和提交:
npm install @polymarket/clob-client-v2 viem
pip install py-clob-client-v2
你也可以直接使用 REST API,但需要自己管理 [EIP-712 订单签名](https://github.com/Polymarket/clob-client-v2/blob/main/src/signing/eip712.ts) 和 [HMAC 身份验证头](https://github.com/Polymarket/clob-client-v2/blob/main/src/signing/hmac.ts)。 请参阅下方的 [REST API 请求头](#rest-api-headers)。
身份验证
CLOB 使用两级身份验证:
| 级别 | 方法 | 用途 |
|---|---|---|
| L1 | EIP-712 签名(私钥) | 创建或派生 API 凭证 |
| L2 | HMAC-SHA256 (API 凭证) | 下单、撤单、查询交易 |
你需要使用私钥一次来派生 L2 凭证(API key、secret、passphrase),这些凭证用于验证所有后续的交易请求。
```typescript TypeScript theme={null} import { ClobClient } from "@polymarket/clob-client-v2"; import { createWalletClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as 0x${string});
const signer = createWalletClient({ account, transport: http() });
// Derive L2 API credentials
const tempClient = new ClobClient({ host: "https://clob.polymarket.com", chain: 137, signer });
const apiCreds = await tempClient.createOrDeriveApiKey();
```python Python theme={null}
from py_clob_client_v2 import ClobClient
import os
private_key = os.getenv("PRIVATE_KEY")
# Derive L2 API credentials
temp_client = ClobClient("https://clob.polymarket.com", key=private_key, chain_id=137)
api_creds = temp_client.create_or_derive_api_key()
签名类型
初始化交易客户端时,你必须指定钱包的签名类型 和 funder 地址:
| 钱包类型 | ID | 使用场景 | Funder 地址 |
|---|---|---|---|
| EOA | 0 |
独立钱包------你自己支付 gas 费(使用 POL 支付 gas) | 你的 EOA 钱包地址 |
| POLY_PROXY | 1 |
现有的 Polymarket 代理钱包流程 | 你的代理钱包地址 |
| GNOSIS_SAFE | 2 |
现有的 Gnosis Safe 钱包流程 | 你的 Safe 钱包地址 |
| POLY_1271 | 3 |
面向新 API 用户的 Deposit Wallet 流程。订单由所有者/会话签名者签名,并通过 ERC-1271 验证 | 你的 Deposit Wallet 地址 |
新 API 用户应使用签名类型 `3`(Deposit Wallet)。现有的 Proxy 和 Safe 用户 不受影响,可以继续使用签名类型 `1` 和 `2`。类型 `0` 仅适用于独立的 EOA 钱包。
初始化交易客户端
```typescript TypeScript theme={null} const client = new ClobClient({ host: "https://clob.polymarket.com", chain: 137, signer, creds: apiCreds, signatureType: 2, // GNOSIS_SAFE funderAddress: "0x...", // Your proxy wallet address }); ```
python
client = ClobClient(
"https://clob.polymarket.com",
key=private_key,
chain_id=137,
creds=api_creds,
signature_type=2, # GNOSIS_SAFE
funder="0x..." # Your proxy wallet address
)
REST API 请求头
如果你直接使用 REST API (不通过 SDK),需要在每个请求中附加身份验证头。
L1 请求头 --- 用于创建或派生 API 凭证:
| 请求头 | 说明 |
|---|---|
POLY_ADDRESS |
你的钱包地址 |
POLY_SIGNATURE |
EIP-712 签名 |
POLY_TIMESTAMP |
Unix 时间戳 |
POLY_NONCE |
请求随机数 |
L2 请求头 --- 用于所有交易操作(下单、撤单、查询):
| 请求头 | 说明 |
|---|---|
POLY_ADDRESS |
你的钱包地址 |
POLY_SIGNATURE |
请求的 HMAC-SHA256 签名 |
POLY_TIMESTAMP |
Unix 时间戳 |
POLY_API_KEY |
你的 API key |
POLY_PASSPHRASE |
你的 API passphrase |
即使使用 L2 身份验证,创建订单的方法仍然需要用户的私钥来进行 EIP-712 订单载荷签名。 L2 凭证用于验证请求本身,但订单必须由密钥签名。
速率限制
CLOB 实施速率限制以确保系统稳定性:
| 范围 | 限制 |
|---|---|
| 一般限制 | 每 10 秒 15,000 个请求 |
POST /order |
峰值 500/秒,持续 80/秒 |
POST /orders (批量) |
峰值 150/秒,持续 35/秒 |
DELETE /order |
峰值 500/秒,持续 80/秒 |
超过这些限制将返回 HTTP 429。请在客户端中实现指数退避。
服务器基础设施
CLOB 撮合引擎运行在以下区域:
- 主服务器:eu-west-2
- 最近的非地区限制区域:eu-west-1
**可申请直接同地协作(co-location)。** 完成 [KYC/KYB 表单](https://forms.gle/Qy39FtiizodXbdLNA)的用户可以申请直接在 `eu-west-2` 中进行同地协作,以获得到 Polymarket 主服务器的最低延迟。完整的地理可用性信息请参阅 [地区限制](/api-reference/geoblock#server-infrastructure)。
本节内容
端到端完成你的第一笔订单 读取订单簿、价格、价差和中间价 订单类型、最小价格单位、创建、取消和查询订单 费用结构、启用费用的市场以及做市商回扣 无需支付 gas 即可执行链上操作 拆分、合并和赎回结果代币 跨链存入和提取资金 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
快速开始
在 Polymarket 上下达你的第一笔订单
本指南将带你完整体验在 Polymarket 上下达订单的全过程。
```bash TypeScript theme={null} npm install @polymarket/clob-client-v2 viem ```
```bash Python theme={null}
pip install py-clob-client-v2
```
</CodeGroup>
生成你的 API 凭证并初始化交易客户端。本示例使用 EOA 钱包(类型 `0`)------你的钱包支付自己的 gas 费用并充当资金账户:
<CodeGroup>
```typescript TypeScript theme={null}
import { ClobClient } from "@polymarket/clob-client-v2";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
const HOST = "https://clob.polymarket.com";
const CHAIN_ID = 137; // Polygon mainnet
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const signer = createWalletClient({ account, transport: http() });
// Derive API credentials
const tempClient = new ClobClient({ host: HOST, chain: CHAIN_ID, signer });
const apiCreds = await tempClient.createOrDeriveApiKey();
// Initialize trading client
const client = new ClobClient({
host: HOST,
chain: CHAIN_ID,
signer,
creds: apiCreds,
signatureType: 0, // EOA
funderAddress: account.address,
});
```
```python Python theme={null}
from py_clob_client_v2 import ClobClient
import os
host = "https://clob.polymarket.com"
chain = 137 # Polygon mainnet
private_key = os.getenv("PRIVATE_KEY")
# Derive API credentials
temp_client = ClobClient(host, key=private_key, chain_id=chain)
api_creds = temp_client.create_or_derive_api_key()
# Initialize trading client
client = ClobClient(
host,
key=private_key,
chain_id=chain,
creds=api_creds,
signature_type=0, # EOA
funder="YOUR_WALLET_ADDRESS"
)
```
</CodeGroup>
<Note>
如果你有 Polymarket.com 账户,你的资金在代理钱包中------请改用签名类型 `1` 或 `2`。详情请见[签名类型](/trading/overview#signature-types)。
</Note>
<Warning>
在交易之前,你的资金账户地址需要 **pUSD**(用于购买结果代币)和 **POL**(用于 gas,如果使用 EOA 类型 `0`)。代理钱包用户(类型 `1` 和 `2`)可以改用 Polymarket 的无 gas 中继器。
</Warning>
从 [Markets API](/market-data/fetching-markets) 获取代币 ID,然后创建并提交你的订单:
<CodeGroup>
```typescript TypeScript theme={null}
import { Side, OrderType } from "@polymarket/clob-client-v2";
const response = await client.createAndPostOrder(
{
tokenID: "YOUR_TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false, // Set to true for multi-outcome markets
},
OrderType.GTC,
);
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```
```python Python theme={null}
from py_clob_client_v2 import OrderArgs, OrderType, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY
response = client.create_and_post_order(
OrderArgs(
token_id="YOUR_TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options=PartialCreateOrderOptions(
tick_size="0.01",
neg_risk=False, # Set to True for multi-outcome markets
),
order_type=OrderType.GTC
)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
```
</CodeGroup>
<Tip>
使用 SDK 的 `getTickSize()` 和 `getNegRisk()` 方法,或从 API 返回的市场对象中查询市场的 `tickSize` 和 `negRisk` 值。
</Tip>
```typescript TypeScript theme={null} // View all open orders const openOrders = await client.getOpenOrders(); console.log(`You have ${openOrders.length} open orders`);
// View your trade history
const trades = await client.getTrades();
console.log(`You've made ${trades.length} trades`);
// Cancel an order
await client.cancelOrder(response.orderID);
```
```python Python theme={null}
# View all open orders
open_orders = client.get_orders()
print(f"You have {len(open_orders)} open orders")
# View your trade history
trades = client.get_trades()
print(f"You've made {len(trades)} trades")
# Cancel an order
client.cancel(order_id=response["orderID"])
```
</CodeGroup>
问题排查
生成的 API 凭证使用了错误的私钥、签名类型或资金账户地址。
* 检查 `signatureType` 是否与你的账户类型匹配(`0`、`1`、`2` 或 `3`)
* 确保 `funder` 与你的钱包类型正确对应
* 如果不确定,请使用 `createOrDeriveApiKey()` 重新生成凭证
你的资金账户地址没有足够的代币:
* **买单(BUY)**: 需要在资金账户地址中有 pUSD
* **卖单(SELL)**: 需要在资金账户地址中有结果代币
* 确保你的 pUSD 余额大于未完成订单中已锁定的金额
你需要批准 Exchange 合约使用你的代币。这通常在你首次交易时通过 Polymarket UI 完成,或使用 CTF 合约的 `setApprovalForAll()` 方法完成。 你的资金账户地址是持有你资金的钱包:
* **EOA(类型 0)**: 直接是你的钱包地址
* **代理钱包(类型 1 或 2)**: 前往 [polymarket.com/settings](https://polymarket.com/settings) 在个人资料下拉菜单中查找钱包地址
如果代理钱包不存在,请先登录 Polymarket.com(钱包在首次登录时部署)。
你正在尝试从受限制的地区下达交易。详情请见[地理限制](/api-reference/geoblock)。
下一步
订单类型、价格精度和错误处理 将订单归属到你的构建者账户以获得交易量积分 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
订单簿
读取订单簿、价格、价差和中间价
订单簿是公开端点------无需身份验证。你可以使用 SDK 或直接通过 REST API 读取价格和流动性。
```typescript TypeScript theme={null} import { ClobClient } from "@polymarket/clob-client-v2";
const client = new ClobClient({ host: "https://clob.polymarket.com", chain: 137 });
```python Python theme={null}
from py_clob_client_v2 import ClobClient
client = ClobClient("https://clob.polymarket.com", chain_id=137)
bash
# Base URL for all orderbook endpoints
https://clob.polymarket.com
获取订单簿
获取代币的完整订单簿,包括所有待成交的买单和卖单价位:
```typescript TypeScript theme={null} const book = await client.getOrderBook("TOKEN_ID");
console.log("Best bid:", book.bids[0]);
console.log("Best ask:", book.asks[0]);
console.log("Tick size:", book.tick_size);
```python Python theme={null}
book = client.get_order_book("TOKEN_ID")
print("Best bid:", book["bids"][0])
print("Best ask:", book["asks"][0])
print("Tick size:", book["tick_size"])
bash
curl "https://clob.polymarket.com/book?token_id=TOKEN_ID"
响应
json
{
"market": "0xbd31dc8a...",
"asset_id": "52114319501245...",
"timestamp": "2023-10-21T08:00:00Z",
"bids": [
{ "price": "0.48", "size": "1000" },
{ "price": "0.47", "size": "2500" }
],
"asks": [
{ "price": "0.52", "size": "800" },
{ "price": "0.53", "size": "1500" }
],
"min_order_size": "5",
"tick_size": "0.01",
"neg_risk": false,
"hash": "0xabc123..."
}
| 字段 | 描述 |
|---|---|
market |
市场的条件 ID |
asset_id |
代币 ID |
bids |
买单按价格排序(最高价优先) |
asks |
卖单按价格排序(最低价优先) |
tick_size |
此市场的最小价格增量 |
min_order_size |
此市场的最小订单大小 |
neg_risk |
是否为多结果(负风险)市场 |
hash |
订单簿状态的哈希值------用于检测变化 |
价格
获取买入或卖出代币的最佳可用价格:
```typescript TypeScript theme={null} const buyPrice = await client.getPrice("TOKEN_ID", "BUY"); console.log("Best ask:", buyPrice.price); // Price you'd pay to buy
const sellPrice = await client.getPrice("TOKEN_ID", "SELL");
console.log("Best bid:", sellPrice.price); // Price you'd receive to sell
```python Python theme={null}
buy_price = client.get_price("TOKEN_ID", "BUY")
print("Best ask:", buy_price["price"])
sell_price = client.get_price("TOKEN_ID", "SELL")
print("Best bid:", sell_price["price"])
bash
# Best price for buying (lowest ask)
curl "https://clob.polymarket.com/price?token_id=TOKEN_ID&side=BUY"
# Best price for selling (highest bid)
curl "https://clob.polymarket.com/price?token_id=TOKEN_ID&side=SELL"
中间价
中间价是最佳买价和最佳卖价的平均值。这是 Polymarket 上显示为市场隐含概率的价格。
```typescript TypeScript theme={null} const midpoint = await client.getMidpoint("TOKEN_ID"); console.log("Midpoint:", midpoint.mid); // e.g., "0.50" ```
python
midpoint = client.get_midpoint("TOKEN_ID")
print("Midpoint:", midpoint["mid"])
bash
curl "https://clob.polymarket.com/midpoint?token_id=TOKEN_ID"
如果买卖价差超过 \$0.10,Polymarket 会显示最后成交价而不是中间价。
价差
价差是最佳卖价和最佳买价之间的差额。价差越小表示市场流动性越好。
```typescript TypeScript theme={null} const spread = await client.getSpread("TOKEN_ID"); console.log("Spread:", spread.spread); // e.g., "0.04" ```
python
spread = client.get_spread("TOKEN_ID")
print("Spread:", spread["spread"])
bash
# Spreads use POST for batch requests
curl -X POST "https://clob.polymarket.com/spreads" \
-H "Content-Type: application/json" \
-d '[{"token_id": "TOKEN_ID"}]'
价格历史
获取代币在各个时间间隔内的历史价格数据:
```typescript TypeScript theme={null} import { PriceHistoryInterval } from "@polymarket/clob-client-v2";
const history = await client.getPricesHistory({
market: "TOKEN_ID", // Note: this param is named "market" but takes a token ID
interval: PriceHistoryInterval.ONE_DAY,
fidelity: 60, // Data points every 60 minutes
});
// Each entry: { t: timestamp, p: price }
history.forEach((point) => {
console.log(${new Date(point.t * 1000).toISOString()}: ${point.p});
});
```python Python theme={null}
history = client.get_prices_history(
market="TOKEN_ID", # Note: this param is named "market" but takes a token ID
interval="1d",
fidelity=60, # Data points every 60 minutes
)
for point in history:
print(f"{point['t']}: {point['p']}")
bash
# By interval (relative to now)
curl "https://clob.polymarket.com/prices-history?market=TOKEN_ID&interval=1d&fidelity=60"
# By timestamp range
curl "https://clob.polymarket.com/prices-history?market=TOKEN_ID&startTs=1697875200&endTs=1697961600"
| 时间间隔 | 描述 |
|---|---|
1h |
最近一小时 |
6h |
最近 6 小时 |
1d |
最近一天 |
1w |
最近一周 |
1m |
最近一个月 |
max |
所有可用数据 |
`interval` 是相对于当前时间的。使用 `startTs` / `endTs` 表示绝对时间范围。它们是互斥的------不要将它们组合使用。
估算成交价格
计算给定大小的市价单的有效成交价格,考虑订单簿深度:
```typescript TypeScript theme={null} import { Side, OrderType } from "@polymarket/clob-client-v2";
// What price would I pay to buy $500 worth?
const price = await client.calculateMarketPrice(
"TOKEN_ID",
Side.BUY,
500, // dollar amount
OrderType.FOK,
);
console.log("Estimated fill price:", price);
```python Python theme={null}
from py_clob_client_v2 import OrderType
price = client.calculate_market_price(
token_id="TOKEN_ID",
side="BUY",
amount=500,
order_type=OrderType.FOK,
)
print("Estimated fill price:", price)
这会遍历订单簿来估算滑点。在提交市价单之前确定订单大小时很有用。
批量请求
所有订单簿查询都有批量变体,可在单个请求中获取多个代币的数据(最多 500 个代币):
| 单个 | 批量 | REST |
|---|---|---|
getOrderBook() |
getOrderBooks() |
POST /books |
getPrice() |
getPrices() |
POST /prices |
getMidpoint() |
getMidpoints() |
POST /midpoints |
getSpread() |
getSpreads() |
POST /spreads |
getLastTradePrice() |
getLastTradesPrices() |
--- |
批量订单簿请求的 `BookParams` 接受 `token_id` 和可选的 `side` 参数来按买价或卖价方向过滤。 ```typescript TypeScript theme={null} import { Side } from "@polymarket/clob-client-v2";
// Fetch prices for multiple tokens
const prices = await client.getPrices([
{ token_id: "TOKEN_A", side: Side.BUY },
{ token_id: "TOKEN_B", side: Side.BUY },
]);
// Returns: { "TOKEN_A": { "BUY": "0.52" }, "TOKEN_B": { "BUY": "0.74" } }
```python Python theme={null}
prices = client.get_prices([
{"token_id": "TOKEN_A", "side": "BUY"},
{"token_id": "TOKEN_B", "side": "BUY"},
])
bash
curl -X POST "https://clob.polymarket.com/prices" \
-H "Content-Type: application/json" \
-d '[
{"token_id": "TOKEN_A", "side": "BUY"},
{"token_id": "TOKEN_B", "side": "BUY"}
]'
最后成交价格
获取代币最近一笔交易的价格和方向:
```typescript TypeScript theme={null} const lastTrade = await client.getLastTradePrice("TOKEN_ID"); console.log(lastTrade.price, lastTrade.side); // e.g., "0.52", "BUY" ```
python
last_trade = client.get_last_trade_price("TOKEN_ID")
print(last_trade["price"], last_trade["side"])
实时更新
对于实时订单簿数据,使用 WebSocket API 而不是轮询。market 频道实时推送订单簿变化、价格更新和交易事件。
连接
typescript
const ws = new WebSocket(
"wss://ws-subscriptions-clob.polymarket.com/ws/market",
);
ws.onopen = () => {
ws.send(
JSON.stringify({
type: "market",
assets_ids: ["TOKEN_ID"],
custom_feature_enabled: true, // enables best_bid_ask, new_market, market_resolved events
}),
);
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.event_type) {
case "book": // full orderbook snapshot
case "price_change": // individual price level update
case "last_trade_price": // new trade executed
case "tick_size_change": // market tick size changed
case "best_bid_ask": // top-of-book update (requires custom_feature_enabled)
case "new_market": // new market created (requires custom_feature_enabled)
case "market_resolved": // market resolved (requires custom_feature_enabled)
}
};
动态订阅和取消订阅
连接后,你可以在不重新连接的情况下更改订阅:
typescript
// Subscribe to additional tokens
ws.send(
JSON.stringify({
assets_ids: ["NEW_TOKEN_ID"],
operation: "subscribe",
}),
);
// Unsubscribe from tokens
ws.send(
JSON.stringify({
assets_ids: ["OLD_TOKEN_ID"],
operation: "unsubscribe",
}),
);
事件类型
| 事件 | 触发时机 | 关键字段 |
|---|---|---|
book |
订阅时 + 当交易影响订单簿时 | bids[], asks[], hash, timestamp |
price_change |
新订单下达或订单取消时 | price_changes[] with price, size, side, best_bid, best_ask |
last_trade_price |
交易执行时 | price, side, size, fee_rate_bps |
tick_size_change |
价格达到 >0.96 或 < 0.04 时 | old_tick_size, new_tick_size |
best_bid_ask |
最优买卖价变化时 | best_bid, best_ask, spread |
new_market |
市场创建时 | question, assets_ids, outcomes |
market_resolved |
市场结算时 | winning_asset_id, winning_outcome |
`best_bid_ask`、`new_market` 和 `market_resolved` 需要在订阅消息中设置 `custom_feature_enabled: true`。 `tick_size_change` 事件对交易机器人至关重要。如果价格增量发生变化而你继续使用旧的价格增量,你的订单将被拒绝。
下一步
使用订单簿数据创建和提交订单 查找你想交易的市场的代币 ID > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
概述
订单类型、最小价格变动单位和订单查询
Polymarket 上的所有订单都以限价单形式表达。市价单通过提交一个可成交价格的限价单来实现------你的订单会立即以盘口最优价格成交。
底层订单原语采用 EIP-712 标准进行结构化、哈希和签名,然后通过 Exchange 合约在链上执行。手动准备订单比较复杂,因此我们推荐使用开源的 TypeScript 或 Python SDK 客户端,它们会为你处理签名和提交。
如果你更喜欢直接使用 REST API,则需要自行管理订单签名。有关构造所需请求头的详细信息,请参阅[身份验证](/api-reference/authentication)。
订单类型
| 类型 | 行为 | 使用场景 |
|---|---|---|
| GTC (Good-Til-Cancelled) | 挂在盘口直到成交或取消 | 被动限价单的默认选项 |
| GTD (Good-Til-Date) | 在指定过期时间(UTC 秒级时间戳)之前有效,除非先被成交或取消 | 在已知事件前自动过期订单 |
| FOK (Fill-Or-Kill) | 必须立即完全成交,否则整个订单被取消 | 全部成交或全部取消 |
| FAK (Fill-And-Kill) | 立即成交尽可能多的份额,然后取消任何未成交的剩余部分 | 部分立即成交 |
- FOK 和 FAK 是市价单类型------它们立即与挂单流动性成交。
- 买入: 指定你想要花费的美元金额
- 卖出: 指定你想要出售的份额数量
- GTC 和 GTD 是限价单类型------它们以你指定的价格挂在盘口。
**GTD 过期时间**: 有一分钟的安全阈值。如果你需要订单在 90 秒后过期,正确的过期值是 `现在 + 1 分钟 + 30 秒`。
Post-Only 订单
Post-only 订单是只会挂在盘口而不会在进入时立即匹配的限价单。
- 如果 post-only 订单会穿过价差(即可立即成交),它将被拒绝而不是执行。
- Post-only 不能 与市价单类型(FOK 或 FAK)组合使用。如果市价单类型发送
postOnly = true,订单将被拒绝。 - Post-only 只能与 GTC 和 GTD 订单类型一起使用。
最小价格变动单位
市场有不同的最小价格增量(最小价格变动单位)。你的订单价格必须符合市场的最小价格变动单位,否则订单将被拒绝。
| 最小价格变动单位 | 价格精度 | 价格示例 |
|---|---|---|
0.1 |
1 位小数 | 0.1, 0.2, 0.5 |
0.01 |
2 位小数 | 0.01, 0.50, 0.99 |
0.001 |
3 位小数 | 0.001, 0.500, 0.999 |
0.0001 |
4 位小数 | 0.0001, 0.5000, 0.9999 |
使用 SDK 检索市场的最小价格变动单位:
```typescript TypeScript theme={null} const tickSize = await client.getTickSize(tokenID); // Returns: "0.1" | "0.01" | "0.001" | "0.0001" ```
python
tick_size = client.get_tick_size(token_id)
# Returns: "0.1" | "0.01" | "0.001" | "0.0001"
你还可以查看 [Markets API](/market-data/fetching-markets) 返回的市场对象上的 `minimum_tick_size` 字段。
Negative Risk
多结果事件(例如"谁会赢得选举?"有 3 个以上候选人)使用不同的交易合约,称为 Neg Risk CTF Exchange 。在这些市场下单时,你必须在订单选项中传递 negRisk: true。
```typescript TypeScript theme={null} const response = await client.createAndPostOrder( { tokenID: "TOKEN_ID", price: 0.5, size: 10, side: Side.BUY, }, { tickSize: "0.01", negRisk: true, // Required for multi-outcome markets }, ); ```
python
from py_clob_client_v2 import OrderArgs, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options=PartialCreateOrderOptions(
tick_size="0.01",
neg_risk=True, # Required for multi-outcome markets
)
)
你可以通过 SDK 或市场对象的 neg_risk 字段检查市场是否使用 negative risk:
```typescript TypeScript theme={null} const isNegRisk = await client.getNegRisk(tokenID); ```
python
is_neg_risk = client.get_neg_risk(token_id)
授权额度
在下单之前,你的资金地址必须已批准 Exchange 合约使用相关代币:
- 买入 : 资金方必须设置大于或等于支出金额的 pUSD 授权额度。
- 卖出 : 资金方必须设置大于或等于出售金额的条件代币授权额度。
这允许 Exchange 合约根据你签名的订单指令执行结算。
有效性检查
系统会持续监控订单以确保它们保持有效。这包括跟踪:
- 底层余额
- 授权额度
任何被发现故意滥用这些检查的 maker 将被列入黑名单。
每个市场的订单下单也有限制。你只能下总额小于或等于每个市场可用余额的订单。例如,如果你的资金钱包中有 500 pUSD,你可以下一个以 $0.50 买入 1000 YES 的订单------但该市场中的任何额外买入订单都会被拒绝,因为你的全部余额已为第一个订单预留。
你可以下单的最大规模是:
maxOrderSize = underlyingAssetBalance − ∑ ( orderSize − orderFillAmount ) \text{maxOrderSize} = \text{underlyingAssetBalance} - \sum(\text{orderSize} - \text{orderFillAmount}) maxOrderSize=underlyingAssetBalance−∑(orderSize−orderFillAmount)
订单查询
所有查询端点都需要 L2 身份验证。Builder 身份验证的客户端也可以使用相同的方法查询归属于其 builder 账户的订单。
获取单个订单
通过订单 ID 检索特定订单的详细信息:
```typescript TypeScript theme={null} const order = await client.getOrder("0xb816482a..."); console.log(order); ```
python
order = client.get_order("0xb816482a...")
print(order)
获取未成交订单
检索你的未成交订单,可选择按市场或资产筛选:
```typescript TypeScript theme={null} // All open orders const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by asset
const assetOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```python Python theme={null}
from py_clob_client_v2 import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(
market="0xbd31dc8a...",
)
)
OpenOrder 对象
每个返回的订单包含以下字段:
| 字段 | 类型 | 描述 |
|---|---|---|
id |
string | 订单 ID |
status |
string | 当前订单状态 |
market |
string | 市场 ID (条件 ID) |
asset_id |
string | 代币 ID |
side |
string | BUY 或 SELL |
original_size |
string | 下单时的原始订单规模 |
size_matched |
string | 已成交数量 |
price |
string | 限价 |
outcome |
string | 可读结果(例如 "Yes"、"No") |
order_type |
string | 订单类型 (GTC、GTD、FOK、FAK) |
maker_address |
string | 资金地址 |
owner |
string | 订单所有者的 API 密钥 |
expiration |
string | 订单过期的 Unix 时间戳(无过期时间为 0) |
associate_trades |
string[] | 此订单部分参与的交易 ID |
created_at |
string | 订单创建的 Unix 时间戳 |
交易历史
当订单被匹配时,会创建一笔交易。交易经历以下状态:
| 状态 | 是否终态? | 描述 |
|---|---|---|
MATCHED |
否 | 已匹配并发送到执行器服务以进行链上提交 |
MINED |
否 | 观察到已在链上挖出,但尚未达到最终性阈值 |
CONFIRMED |
是 | 达到强概率最终性------交易成功 |
RETRYING |
否 | 交易失败(回滚或重组)------运营商正在重试 |
FAILED |
是 | 交易永久失败且不再重试 |
Trade 对象
每笔交易包含以下字段:
| 字段 | 类型 | 描述 |
|---|---|---|
id |
string | 交易 ID |
taker_order_id |
string | Taker 订单 ID (哈希) |
market |
string | 市场 ID (条件 ID) |
asset_id |
string | 代币 ID |
side |
string | BUY 或 SELL |
size |
string | 交易规模 |
fee_rate_bps |
string | 以基点表示的费率 |
price |
string | 交易价格 |
status |
string | 交易状态(见上表) |
match_time |
string | 交易匹配的 Unix 时间戳 |
last_update |
string | 最后状态更新的 Unix 时间戳 |
outcome |
string | 可读结果(例如 "Yes"、"No") |
owner |
string | 交易所有者的 API 密钥 ID |
maker_address |
string | 资金地址 |
trader_side |
string | 你在此交易中是 TAKER 还是 MAKER |
transaction_hash |
string | 链上交易哈希(挖矿后可用) |
maker_orders |
array | 与此交易匹配的 maker 订单数组(见下文) |
MakerOrder 字段
maker_orders 数组中的每个条目包含:
| 字段 | 类型 | 描述 |
|---|---|---|
order_id |
string | Maker 订单 ID (哈希) |
owner |
string | Maker 的 API 密钥 ID |
maker_address |
string | Maker 的资金地址 |
matched_amount |
string | 此交易中匹配的数量 |
price |
string | Maker 订单价格 |
fee_rate_bps |
string | Maker 费率(基点) |
asset_id |
string | 代币 ID |
outcome |
string | 结果名称 |
side |
string | BUY 或 SELL |
使用 SDK 检索你的交易:
```typescript TypeScript theme={null} // All trades const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
// With pagination
const paginatedTrades = await client.getTradesPaginated({
market: "0xbd31dc8a...",
});
```python Python theme={null}
from py_clob_client_v2 import TradeParams
# All trades
trades = client.get_trades()
# Filtered by market
market_trades = client.get_trades(
TradeParams(
market="0xbd31dc8a...",
)
)
心跳
心跳端点维护会话存活以确保订单安全。如果在 10 秒 内(最多有 5 秒缓冲)未收到有效心跳,你的所有未成交订单将被取消。
```typescript TypeScript theme={null} // Send heartbeats in a loop let heartbeatId = ""; setInterval(async () => { const resp = await client.postHeartbeat(heartbeatId); heartbeatId = resp.heartbeat_id; }, 5000); ```
python
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
- 在每个请求中,包含你收到的最新
heartbeat_id。对于你的第一个请求,使用空字符串。 - 如果你发送无效或过期的
heartbeat_id,服务器会响应400 Bad Request并在响应中提供正确的heartbeat_id。更新你的客户端并重试。
订单评分
检查你的挂单是否符合 maker 返佣评分条件:
```typescript TypeScript theme={null} // Single order const scoring = await client.isOrderScoring({ orderId: "0x..." }); console.log(scoring); // { scoring: true }
// Multiple orders
const batchScoring = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```python Python theme={null}
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
# Single order
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
# Multiple orders
batch_scoring = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
链上订单信息
当交易在链上结算时,Exchange 合约会发出 OrderFilled 事件,包含以下字段:
| 字段 | 描述 |
|---|---|
orderHash |
已成交订单的唯一哈希 |
maker |
生成订单和资金来源的用户 |
taker |
成交订单的用户,或在成交多个限价单时为 Exchange 合约 |
makerAssetId |
给出的资产 ID。如果为 0,订单是买入(用 pUSD 换取结果代币) |
takerAssetId |
收到的资产 ID。如果为 0,订单是卖出(用结果代币换取 pUSD) |
makerAmountFilled |
给出的资产数量 |
takerAmountFilled |
收到的资产数量 |
fee |
订单 maker 支付的费用 |
错误消息
下单时,如果无法下单,响应可能包含 errorMsg。如果 success 为 false,则发生服务器端错误:
| 错误 | 描述 |
|---|---|
INVALID_ORDER_MIN_TICK_SIZE |
价格不符合市场的最小价格变动单位 |
INVALID_ORDER_MIN_SIZE |
订单规模低于最小阈值 |
INVALID_ORDER_DUPLICATED |
相同的订单已经下过 |
INVALID_ORDER_NOT_ENOUGH_BALANCE |
资金方没有足够的余额或授权额度 |
INVALID_ORDER_EXPIRATION |
过期时间戳在过去 |
INVALID_ORDER_ERROR |
插入订单时的系统错误 |
INVALID_POST_ONLY_ORDER_TYPE |
Post-only 标志与市价单类型(FOK/FAK)一起使用 |
INVALID_POST_ONLY_ORDER |
Post-only 订单会穿过盘口 |
EXECUTION_ERROR |
执行交易时的系统错误 |
ORDER_DELAYED |
由于市场条件订单下单延迟 |
DELAYING_ORDER_ERROR |
延迟订单时的系统错误 |
FOK_ORDER_NOT_FILLED_ERROR |
FOK 订单无法完全成交 |
MARKET_NOT_READY |
市场尚未接受订单 |
插入状态
当订单成功下单时,响应包含 status 字段:
| 状态 | 描述 |
|---|---|
matched |
订单已下单并与挂单匹配 |
live |
订单已下单并挂在盘口 |
delayed |
订单可成交但受匹配延迟限制 |
unmatched |
订单可成交但延迟失败------下单仍然成功 |
安全性
Polymarket 的 Exchange 合约已由 Chainsecurity 审计(查看审计报告)。
运营商的权限仅限于订单匹配和确保正确排序。运营商无法设置价格或执行未经授权的交易。
下一步
构建、签名和提交订单 取消单个、多个或所有订单 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
创建订单
构建、签名并提交订单
Polymarket 上的所有订单都以限价单形式表达。市价单通过提交一个具有可成交价格的限价单来实现 --- 你的订单将立即以账本上的最佳可用价格执行。
SDK 会为你处理 EIP-712 签名和提交。如果你更喜欢直接使用 REST API,请参阅[身份验证](/api-reference/authentication)以了解如何构建所需的请求头,以及[API 参考](/api-reference/introduction)以查看完整的端点文档,包括原始订单对象字段和请求/响应模式。
订单类型
| 类型 | 行为 | 用例 |
|---|---|---|
| GTC | Good-Til-Cancelled --- 在账本上保留,直到成交或取消 | 限价单的默认类型 |
| GTD | Good-Til-Date --- 活跃至指定的到期时间 | 在已知事件前自动过期 |
| FOK | Fill-Or-Kill --- 必须立即完全成交,否则取消 | 全部成交或全部取消的市价单 |
| FAK | Fill-And-Kill --- 立即成交可用部分,取消剩余部分 | 部分成交的市价单 |
- GTC 和 GTD 是限价单类型 --- 它们以你指定的价格在账本上等待成交。
- FOK 和 FAK 是市价单类型 --- 它们立即对现有流动性执行。
- BUY: 指定你想要花费的美元金额
- SELL: 指定你想要卖出的份额数量
限价单
下单限价单最简单的方式 --- 在一次调用中创建、签名并提交:
```typescript TypeScript theme={null} import { ClobClient, Side, OrderType } from "@polymarket/clob-client-v2";
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: false,
},
OrderType.GTC,
);
console.log("Order ID:", response.orderID);
console.log("Status:", response.status);
```python Python theme={null}
from py_clob_client_v2 import OrderArgs, OrderType, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
order_type=OrderType.GTC
)
print("Order ID:", response["orderID"])
print("Status:", response["status"])
两步操作 - 先签名再提交
如果需要更多控制,可以将签名和提交分开。这对批量订单或自定义提交逻辑很有用:
```typescript TypeScript theme={null} // Step 1: Create and sign locally const signedOrder = await client.createOrder( { tokenID: "TOKEN_ID", price: 0.5, size: 10, side: Side.BUY, }, { tickSize: "0.01", negRisk: false }, );
// Step 2: Submit to the CLOB
const response = await client.postOrder(signedOrder, OrderType.GTC);
```python Python theme={null}
# Step 1: Create and sign locally
signed_order = client.create_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)
)
# Step 2: Submit to the CLOB
response = client.post_order(signed_order, OrderType.GTC)
GTD 订单 - 定时过期
GTD 订单会在指定时间自动过期。适用于围绕已知事件进行报价。
```typescript TypeScript theme={null} // Expire in 1 hour (+ 60s security threshold buffer) const expiration = Math.floor(Date.now() / 1000) + 60 + 3600;
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 10,
side: Side.BUY,
expiration,
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTD,
);
```python Python theme={null}
import time
# Expire in 1 hour (+ 60s security threshold buffer)
expiration = int(time.time()) + 60 + 3600
response = client.create_and_post_order(
OrderArgs(
token_id="TOKEN_ID",
price=0.50,
size=10,
side=BUY,
expiration=expiration,
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
order_type=OrderType.GTD
)
GTD 过期时间有一分钟的安全阈值。要设置 N 秒的有效生命周期,请使用 `now + 60 + N`。例如,对于 30 秒的有效生命周期,将过期时间设置为 `now + 60 + 30`。
市价单
市价单使用 FOK 或 FAK 类型立即对现有流动性执行:
```typescript TypeScript theme={null} import { Side, OrderType } from "@polymarket/clob-client-v2";
// FOK BUY: spend exactly $100 or cancel entirely
const buyOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.BUY,
amount: 100, // dollar amount
price: 0.5, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(buyOrder, OrderType.FOK);
// FOK SELL: sell exactly 200 shares or cancel entirely
const sellOrder = await client.createMarketOrder(
{
tokenID: "TOKEN_ID",
side: Side.SELL,
amount: 200, // number of shares
price: 0.45, // worst-price limit (slippage protection)
},
{ tickSize: "0.01", negRisk: false },
);
await client.postOrder(sellOrder, OrderType.FOK);
```python Python theme={null}
from py_clob_client_v2.order_builder.constants import BUY, SELL
from py_clob_client_v2 import MarketOrderArgs, OrderType, PartialCreateOrderOptions
# FOK BUY: spend exactly $100 or cancel entirely
buy_order = client.create_market_order(
order_args=MarketOrderArgs(
token_id="TOKEN_ID",
side=BUY,
amount=100, # dollar amount
price=0.50, # worst-price limit (slippage protection)
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
)
client.post_order(buy_order, OrderType.FOK)
# FOK SELL: sell exactly 200 shares or cancel entirely
sell_order = client.create_market_order(
order_args=MarketOrderArgs(
token_id="TOKEN_ID",
side=SELL,
amount=200, # number of shares
price=0.45, # worst-price limit (slippage protection)
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
)
client.post_order(sell_order, OrderType.FOK)
- FOK --- 完全成交或取消整个订单
- FAK --- 成交可用部分,取消剩余部分
市价单上的 price 字段作为最差价格限制(滑点保护),而不是目标执行价格。
一步市价单
为了方便,createAndPostMarketOrder 在一次调用中处理创建、签名和提交:
```typescript TypeScript theme={null} const response = await client.createAndPostMarketOrder( { tokenID: "TOKEN_ID", side: Side.BUY, amount: 100, price: 0.5, }, { tickSize: "0.01", negRisk: false }, OrderType.FOK, ); ```
python
from py_clob_client_v2 import MarketOrderArgs, OrderType, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY
response = client.create_and_post_market_order(
order_args=MarketOrderArgs(
token_id="TOKEN_ID",
side=BUY,
amount=100,
price=0.50,
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
order_type=OrderType.FOK,
)
Post-Only 订单
Post-Only 订单保证你始终是做市方。如果订单会立即匹配(跨越价差),它将被拒绝而不是执行。
```typescript TypeScript theme={null} const response = await client.postOrder(signedOrder, OrderType.GTC, true); ```
python
response = client.post_order(signed_order, OrderType.GTC, post_only=True)
- 仅适用于 GTC 和 GTD 订单类型
- 如果与 FOK 或 FAK 结合使用将被拒绝
批量订单
在单个请求中最多下达 15 个订单:
```typescript TypeScript theme={null} import { OrderType, Side, PostOrdersArgs } from "@polymarket/clob-client-v2";
const orders: PostOrdersArgs[] = [
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.48,
side: Side.BUY,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
{
order: await client.createOrder(
{
tokenID: "TOKEN_ID",
price: 0.52,
side: Side.SELL,
size: 500,
},
{ tickSize: "0.01", negRisk: false },
),
orderType: OrderType.GTC,
},
];
const response = await client.postOrders(orders);
```python Python theme={null}
from py_clob_client_v2 import OrderArgs, OrderType, PostOrdersV2Args, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY, SELL
response = client.post_orders([
PostOrdersV2Args(
order=client.create_order(OrderArgs(
price=0.48,
size=500,
side=BUY,
token_id="TOKEN_ID",
), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)),
orderType=OrderType.GTC,
),
PostOrdersV2Args(
order=client.create_order(OrderArgs(
price=0.52,
size=500,
side=SELL,
token_id="TOKEN_ID",
), options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False)),
orderType=OrderType.GTC,
),
])
订单选项
每个订单都需要两个特定于市场的选项:tickSize 和 negRisk。有关签名类型(0 = EOA, 1 = POLY_PROXY, 2 = GNOSIS_SAFE)的详细信息,请参阅身份验证。
最小价格变动单位
你的订单价格必须符合市场的最小价格变动单位,否则订单将被拒绝。
| Tick Size | Precision | Example Prices |
|---|---|---|
0.1 |
1 位小数 | 0.1, 0.2, 0.5 |
0.01 |
2 位小数 | 0.01, 0.50, 0.99 |
0.001 |
3 位小数 | 0.001, 0.500, 0.999 |
0.0001 |
4 位小数 | 0.0001, 0.5000, 0.9999 |
```typescript TypeScript theme={null} const tickSize = await client.getTickSize("TOKEN_ID"); ```
python
tick_size = client.get_tick_size("TOKEN_ID")
Negative Risk
多结果事件(3 个及以上结果)使用 Neg Risk CTF Exchange。对于这些市场,请传递 negRisk: true。
```typescript TypeScript theme={null} const isNegRisk = await client.getNegRisk("TOKEN_ID"); ```
python
is_neg_risk = client.get_neg_risk("TOKEN_ID")
这两个值也可以在市场对象上找到:`minimum_tick_size` 和 `neg_risk`。
前提条件
在下单之前,你的资金地址必须已批准 Exchange 合约使用相关代币:
- BUY 订单: pUSD 授权额度 >= 花费金额
- SELL 订单: 条件代币授权额度 >= 卖出金额
订单大小受可用余额限制,需减去现有未完成订单所保留的金额:
maxOrderSize = balance − ∑ ( openOrderSize − filledAmount ) \text{maxOrderSize} = \text{balance} - \sum(\text{openOrderSize} - \text{filledAmount}) maxOrderSize=balance−∑(openOrderSize−filledAmount)
订单会持续监控有效性 --- 余额和授权额度都会实时跟踪。任何做市方故意滥用这些检查将被列入黑名单。
体育市场
体育市场有额外的行为:
- 比赛开始后,未成交的限价单将自动取消,在官方开始时间清空整个订单簿
- 可成交订单在匹配前有 3 秒的下单延迟
- 比赛开始时间可能会变动 --- 请密切监控你的订单,因为如果开始时间意外变化,订单可能不会被清除
响应
成功下单后返回:
json
{
"success": true,
"errorMsg": "",
"orderID": "0xabc123...",
"takingAmount": "",
"makingAmount": "",
"status": "live",
"transactionsHashes": [],
"tradeIDs": []
}
状态
| Status | Description |
|---|---|
live |
订单在账本上等待成交 |
matched |
订单立即与现有订单匹配 |
delayed |
可成交订单受匹配延迟影响 |
unmatched |
可成交但延迟失败 --- 下单仍然成功 |
错误消息
| Error | Description |
|---|---|
INVALID_ORDER_MIN_TICK_SIZE |
价格不符合市场的最小价格变动单位 |
INVALID_ORDER_MIN_SIZE |
订单大小低于最小阈值 |
INVALID_ORDER_DUPLICATED |
相同的订单已经下达 |
INVALID_ORDER_NOT_ENOUGH_BALANCE |
余额或授权额度不足 |
INVALID_ORDER_EXPIRATION |
过期时间戳已过期 |
INVALID_POST_ONLY_ORDER_TYPE |
Post-only 与 FOK/FAK 结合使用 |
INVALID_POST_ONLY_ORDER |
Post-only 订单会跨越账本 |
FOK_ORDER_NOT_FILLED_ERROR |
FOK 订单无法完全成交 |
INVALID_ORDER_ERROR |
插入订单时的系统错误 |
EXECUTION_ERROR |
执行交易时的系统错误 |
ORDER_DELAYED |
由于市场条件导致订单匹配延迟 |
DELAYING_ORDER_ERROR |
延迟订单时的系统错误 |
MARKET_NOT_READY |
市场尚未接受订单 |
心跳
心跳端点维持会话活跃性。如果在 10 秒 内(带 5 秒缓冲)未收到有效心跳,所有未完成订单将被取消。
```typescript TypeScript theme={null} let heartbeatId = ""; setInterval(async () => { const resp = await client.postHeartbeat(heartbeatId); heartbeatId = resp.heartbeat_id; }, 5000); ```
python
import time
heartbeat_id = ""
while True:
resp = client.post_heartbeat(heartbeat_id)
heartbeat_id = resp["heartbeat_id"]
time.sleep(5)
- 在每个请求中包含最新的
heartbeat_id。首次请求使用空字符串。 - 如果发送过期的 ID,服务器会响应
400并返回正确的 ID。更新后重试。
下一步
取消单个、多个或所有未完成订单 将订单归因到你的构建者账户以获得交易量积分 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
取消订单
取消单个、多个或所有未完成订单
所有取消端点都需要 L2 身份验证。响应始终包含 canceled(已取消订单 ID 列表)和 not_canceled(订单 ID 到失败原因的映射)。
取消单个订单
```typescript TypeScript theme={null} const resp = await client.cancelOrder("0xb816482a..."); console.log(resp); // { canceled: ["0xb816482a..."], not_canceled: {} } ```
python
resp = client.cancel(order_id="0xb816482a...")
print(resp)
# {"canceled": ["0xb816482a..."], "not_canceled": {}}
bash
curl -X DELETE "https://clob.polymarket.com/order" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"orderID": "0xb816482a..."}'
取消多个订单
```typescript TypeScript theme={null} const resp = await client.cancelOrders(["0xb816482a...", "0xc927593b..."]); ```
python
resp = client.cancel_orders([
"0xb816482a...",
"0xc927593b...",
])
bash
curl -X DELETE "https://clob.polymarket.com/orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '["0xb816482a...", "0xc927593b..."]'
取消所有订单
取消所有市场中的每个未完成订单:
```typescript TypeScript theme={null} const resp = await client.cancelAll(); ```
python
resp = client.cancel_all()
bash
curl -X DELETE "https://clob.polymarket.com/cancel-all" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..."
按市场取消
取消特定市场的所有订单,可选择性地筛选到单个代币。market 和 asset_id 都是可选的------同时省略两者将取消所有订单。
```typescript TypeScript theme={null} const resp = await client.cancelMarketOrders({ market: "0xbd31dc8a...", // optional: condition ID asset_id: "52114319501245...", // optional: specific token }); ```
python
resp = client.cancel_market_orders(
market="0xbd31dc8a...",
asset_id="52114319501245...", # optional
)
bash
curl -X DELETE "https://clob.polymarket.com/cancel-market-orders" \
-H "Content-Type: application/json" \
-H "POLY_ADDRESS: ..." \
-H "POLY_SIGNATURE: ..." \
-H "POLY_TIMESTAMP: ..." \
-H "POLY_API_KEY: ..." \
-H "POLY_PASSPHRASE: ..." \
-d '{"market": "0xbd31dc8a...", "asset_id": "52114319501245..."}'
查询订单
获取单个订单
```typescript TypeScript theme={null} const order = await client.getOrder("0xb816482a..."); console.log(order.status, order.size_matched); ```
python
order = client.get_order("0xb816482a...")
print(order["status"], order["size_matched"])
获取未完成订单
检索所有未完成订单,可选择性地按市场或代币筛选:
```typescript TypeScript theme={null} // All open orders const orders = await client.getOpenOrders();
// Filtered by market
const marketOrders = await client.getOpenOrders({
market: "0xbd31dc8a...",
});
// Filtered by token
const tokenOrders = await client.getOpenOrders({
asset_id: "52114319501245...",
});
```python Python theme={null}
from py_clob_client_v2 import OpenOrderParams
# All open orders
orders = client.get_orders()
# Filtered by market
market_orders = client.get_orders(
OpenOrderParams(market="0xbd31dc8a...")
)
OpenOrder 对象
| 字段 | 类型 | 描述 |
|---|---|---|
id |
string | 订单 ID |
status |
string | 当前订单状态 |
market |
string | Condition ID |
asset_id |
string | Token ID |
side |
string | BUY 或 SELL |
original_size |
string | 下单时的数量 |
size_matched |
string | 已成交数量 |
price |
string | 限价 |
outcome |
string | 人类可读的结果(例如,"Yes","No") |
order_type |
string | 订单类型(GTC, GTD, FOK, FAK) |
maker_address |
string | 资金提供者地址 |
owner |
string | 订单所有者的 API key |
associate_trades |
string[] | 此订单包含的交易 ID |
expiration |
string | Unix 过期时间戳(如果没有则为 0) |
created_at |
string | Unix 创建时间戳 |
交易历史
当订单匹配时,会创建一笔交易。交易经历以下状态:
| Status | Terminal | Description |
|---|---|---|
MATCHED |
No | 已匹配并发送至链上提交 |
MINED |
No | 已在链上挖出,尚未最终确认 |
CONFIRMED |
Yes | 已达到最终性------交易成功 |
RETRYING |
No | 交易失败------正在重试 |
FAILED |
Yes | 永久失败 |
```typescript TypeScript theme={null} // All trades const trades = await client.getTrades();
// Filtered by market
const marketTrades = await client.getTrades({
market: "0xbd31dc8a...",
});
```python Python theme={null}
from py_clob_client_v2 import TradeParams
trades = client.get_trades()
market_trades = client.get_trades(
TradeParams(market="0xbd31dc8a...")
)
其他筛选参数: id, maker_address, asset_id, before, after。
对于大型结果集,使用分页变体:
```typescript TypeScript theme={null} const page = await client.getTradesPaginated({ market: "0xbd31dc8a..." }); console.log(page.trades, page.count); // trades array + total count ```
python
page = client.get_trades_paginated(TradeParams(market="0xbd31dc8a..."))
Trade 对象
| 字段 | 类型 | 描述 |
|---|---|---|
id |
string | 交易 ID |
taker_order_id |
string | Taker 订单哈希 |
market |
string | Condition ID |
asset_id |
string | Token ID |
side |
string | BUY 或 SELL |
size |
string | 交易数量 |
price |
string | 执行价格 |
fee_rate_bps |
string | 费率(基点) |
status |
string | 交易状态(见上表) |
match_time |
string | 匹配时的 Unix 时间戳 |
last_update |
string | 最后状态更改的 Unix 时间戳 |
outcome |
string | 人类可读的结果(例如,"Yes") |
maker_address |
string | Maker 的资金提供者地址 |
owner |
string | 交易所有者的 API key |
transaction_hash |
string | 链上交易哈希 |
bucket_index |
number | 用于交易对账的索引 |
trader_side |
string | TAKER 或 MAKER |
maker_orders |
MakerOrder[] | 填充此交易的 Maker 订单 |
由于 gas 限制,单笔交易可能会被拆分到多个链上交易中。使用 `bucket_index` 和 `match_time` 将相关交易对账回单个逻辑交易。
订单评分
检查你的挂单是否符合 maker 返利评分资格:
```typescript TypeScript theme={null} // Single order const scoring = await client.isOrderScoring({ orderId: "0x..." });
// Multiple orders
const batch = await client.areOrdersScoring({
orderIds: ["0x...", "0x..."],
});
```python Python theme={null}
from py_clob_client_v2 import OrderScoringParams, OrdersScoringParams
scoring = client.is_order_scoring(
OrderScoringParams(orderId="0x...")
)
batch = client.are_orders_scoring(
OrdersScoringParams(orderIds=["0x...", "0x..."])
)
下一步
将订单归属到你的 Builder 账户以获得交易量信用 了解费用结构和 Maker 返利 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
订单归属
将订单归属到你的 builder code,以获得交易量积分和手续费奖励
订单归属通过将你的 builder code 附加到每个订单,将交易计入你的 builder 账户。这使你能够:
- 在 Builder 排行榜上追踪交易量
- 通过 Builder Program 获得手续费奖励
- 通过 Data API 监控绩效
Builder Code
你的 builder code 是一个与你的 builder 资料关联的 bytes32 标识符。可以在 polymarket.com/settings?tab=builder 中找到。
这是归属所需的唯一凭证 --- 无需 HMAC 签名、无需单独的 API key,也不需要特殊的请求标头。
Builder code 是公开标识符 --- 它们会出现在你归属的每个订单的链上 `builder` 字段中。只有你能控制哪些订单包含你的 code,所以请将其限定在你自己拥有的应用中。
附加 Builder Code
在你提交的每个订单的订单结构中传入 builderCode。SDK 会将其序列化到链上订单的 builder 字段,协议会将每一笔匹配的交易归属到你的资料。
```typescript TypeScript theme={null} import { ClobClient, Side, OrderType } from "@polymarket/clob-client-v2";
const client = new ClobClient({
host: "https://clob.polymarket.com",
chain: 137,
signer,
creds: apiCreds,
signatureType: 2,
funderAddress,
});
const response = await client.createAndPostOrder(
{
tokenID: "0x...",
price: 0.55,
size: 100,
side: Side.BUY,
builderCode: "0xabc123...", // your builder code from polymarket.com/settings?tab=builder
},
{ tickSize: "0.01", negRisk: false },
OrderType.GTC,
);
```python Python theme={null}
from py_clob_client_v2 import ClobClient
from py_clob_client_v2 import OrderArgs, OrderType, PartialCreateOrderOptions
from py_clob_client_v2.order_builder.constants import BUY
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=private_key,
creds=api_creds,
signature_type=2,
funder=funder_address,
)
response = client.create_and_post_order(
OrderArgs(
token_id="0x...",
price=0.55,
size=100,
side=BUY,
builder_code="0xabc123...", # your builder code from polymarket.com/settings?tab=builder
),
options=PartialCreateOrderOptions(tick_size="0.01", neg_risk=False),
order_type=OrderType.GTC,
)
每个附加了 builderCode 的订单都会被归属到你的 builder 资料 --- 无需额外配置。
验证归属
查询归属到你的 builder code 的交易:
```typescript TypeScript theme={null} const trades = await client.getBuilderTrades();
// Filtered by market
const marketTrades = await client.getBuilderTrades({
market: "0xbd31dc8a...",
});
```python Python theme={null}
trades = client.get_builder_trades()
market_trades = client.get_builder_trades(
market="0xbd31dc8a..."
)
每个 BuilderTrade 包括:id、market、assetId、side、size、price、status、outcome、owner、maker、builder、transactionHash、matchTime、fee 和 feeUsdc。
故障排查
* 确认你的 `builderCode` 已正确附加到每个订单 * 检查订单是否已被撮合(而不仅仅是下单) * 交易量在排行榜上显示最多可能需要 24 小时 验证该 code 与 [Builder 资料](https://polymarket.com/settings?tab=builder)中显示的一致。Builder code 是以 `0x` 开头的 `bytes32` 十六进制值。
下一步
了解 Builder Program 的等级和奖励 构建、签名和提交订单 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
费用
了解 Polymarket 的交易费用
Polymarket 对某些市场收取少量 Taker 费用。费用由协议设定并在撮合时应用 --- 你无需在订单中包含费用信息。这些费用资助 Maker 返利计划,每天将费用重新分配给做市商,以激励更深的流动性和更紧的价差。
地缘政治和世界事件市场零费用。 Polymarket 不会对这些市场的交易活动收取费用或从中获利。存入或提取 USDC 也无 Polymarket 费用(尽管 Coinbase 或 MoonPay 等中介机构可能会收取自己的费用)。
费用按市场在撮合时确定。启用费用的市场在市场对象上有 `feesEnabled` 设置为 `true`。使用 `getClobMarketInfo(conditionID)` 查询任何市场的费用参数。
费用结构
费用使用以下公式计算:
text
fee = C × feeRate × p × (1 - p)
其中 C = 交易的份额数量,p = 份额价格。
Maker 不收取任何费用。 只有 Taker 支付费用。不同市场类别的费用参数有所不同:
| 类别 | Taker Fee Rate | Maker Fee Rate | Maker 返利 |
|---|---|---|---|
| 加密货币 | 0.07 | 0 | 20% |
| 体育 | 0.03 | 0 | 25% |
| 金融 | 0.04 | 0 | 25% |
| 政治 | 0.04 | 0 | 25% |
| 经济 | 0.05 | 0 | 25% |
| 文化 | 0.05 | 0 | 25% |
| 天气 | 0.05 | 0 | 25% |
| 其他 / 通用 | 0.05 | 0 | 25% |
| Mentions | 0.04 | 0 | 25% |
| 科技 | 0.04 | 0 | 25% |
| 地缘政治 | 0 | 0 | --- |
Taker 费用以 USDC 计算,并根据份额价格而变化。费用金额(以 USDC 计)关于 50% 概率对称 --- 30¢ 的交易与 70¢ 的交易产生相同的美元费用。
费用表 - 100份额
| 价格 | 交易价值 | Taker 费用 (USDC) | | ------ | ---- | --------------- | | \0.01 \| \\1 | \0.07 \| \| \\0.05 | \5 \| \\0.33 | | \0.10 \| \\10 | \0.63 \| \| \\0.15 | \15 \| \\0.89 | | \0.20 \| \\20 | \1.12 \| \| \\0.25 | \25 \| \\1.31 | | \0.30 \| \\30 | \1.47 \| \| \\0.35 | \35 \| \\1.59 | | \0.40 \| \\40 | \1.68 \| \| \\0.45 | \45 \| \\1.73 | | \0.50 \| \\50 | \1.75 \| \| \\0.55 | \55 \| \\1.73 | | \0.60 \| \\60 | \1.68 \| \| \\0.65 | \65 \| \\1.59 | | \0.70 \| \\70 | \1.47 \| \| \\0.75 | \75 \| \\1.31 | | \0.80 \| \\80 | \1.12 \| \| \\0.85 | \85 \| \\0.89 | | \0.90 \| \\90 | \0.63 \| \| \\0.95 | \95 \| \\0.33 | | \0.99 \| \\99 | \$0.07 |
费用(USDC)在**50%** 概率时达到峰值(\$1.75),并向两端对称递减。
| 价格 | 交易价值 | Taker 费用 (USDC) | | ------ | ---- | --------------- | | \0.01 \| \\1 | \0.03 \| \| \\0.05 | \5 \| \\0.14 | | \0.10 \| \\10 | \0.27 \| \| \\0.15 | \15 \| \\0.38 | | \0.20 \| \\20 | \0.48 \| \| \\0.25 | \25 \| \\0.56 | | \0.30 \| \\30 | \0.63 \| \| \\0.35 | \35 \| \\0.68 | | \0.40 \| \\40 | \0.72 \| \| \\0.45 | \45 \| \\0.74 | | \0.50 \| \\50 | \0.75 \| \| \\0.55 | \55 \| \\0.74 | | \0.60 \| \\60 | \0.72 \| \| \\0.65 | \65 \| \\0.68 | | \0.70 \| \\70 | \0.63 \| \| \\0.75 | \75 \| \\0.56 | | \0.80 \| \\80 | \0.48 \| \| \\0.85 | \85 \| \\0.38 | | \0.90 \| \\90 | \0.27 \| \| \\0.95 | \95 \| \\0.14 | | \0.99 \| \\99 | \$0.03 |
费用(USDC)在**50%** 概率时达到峰值(\$0.75),并向两端对称递减。
| 价格 | 交易价值 | Taker 费用 (USDC) | | ------ | ---- | --------------- | | \0.01 \| \\1 | \0.04 \| \| \\0.05 | \5 \| \\0.19 | | \0.10 \| \\10 | \0.36 \| \| \\0.15 | \15 \| \\0.51 | | \0.20 \| \\20 | \0.64 \| \| \\0.25 | \25 \| \\0.75 | | \0.30 \| \\30 | \0.84 \| \| \\0.35 | \35 \| \\0.91 | | \0.40 \| \\40 | \0.96 \| \| \\0.45 | \45 \| \\0.99 | | \0.50 \| \\50 | \1.00 \| \| \\0.55 | \55 \| \\0.99 | | \0.60 \| \\60 | \0.96 \| \| \\0.65 | \65 \| \\0.91 | | \0.70 \| \\70 | \0.84 \| \| \\0.75 | \75 \| \\0.75 | | \0.80 \| \\80 | \0.64 \| \| \\0.85 | \85 \| \\0.51 | | \0.90 \| \\90 | \0.36 \| \| \\0.95 | \95 \| \\0.19 | | \0.99 \| \\99 | \$0.04 |
费用(USDC)在**50%** 概率时达到峰值(\$1.00),并向两端对称递减。
| 价格 | 交易价值 | Taker 费用 (USDC) | | ------ | ---- | --------------- | | \0.01 \| \\1 | \0.05 \| \| \\0.05 | \5 \| \\0.24 | | \0.10 \| \\10 | \0.45 \| \| \\0.15 | \15 \| \\0.64 | | \0.20 \| \\20 | \0.80 \| \| \\0.25 | \25 \| \\0.94 | | \0.30 \| \\30 | \1.05 \| \| \\0.35 | \35 \| \\1.14 | | \0.40 \| \\40 | \1.20 \| \| \\0.45 | \45 \| \\1.24 | | \0.50 \| \\50 | \1.25 \| \| \\0.55 | \55 \| \\1.24 | | \0.60 \| \\60 | \1.20 \| \| \\0.65 | \65 \| \\1.14 | | \0.70 \| \\70 | \1.05 \| \| \\0.75 | \75 \| \\0.94 | | \0.80 \| \\80 | \0.80 \| \| \\0.85 | \85 \| \\0.64 | | \0.90 \| \\90 | \0.45 \| \| \\0.95 | \95 \| \\0.24 | | \0.99 \| \\99 | \$0.05 |
费用(USDC)在**50%** 概率时达到峰值(\$1.25),并向两端对称递减。
费用精度
费用四舍五入到5位小数。收取的最小费用为 0.00001 USDC。任何更小的金额都会四舍五入为零,因此接近极端价格的非常小的交易可能根本不产生费用。
费用处理
费用由协议在撮合时自动计算和应用 --- 你无需在订单中包含任何费用信息。SDK 会自动处理所有细节。
要查询特定市场的费用参数,请使用 getClobMarketInfo(conditionID):
```typescript TypeScript theme={null} const info = await client.getClobMarketInfo(conditionID); // info.fd = { r: feeRate, e: exponent, to: takerOnly } ```
python
info = client.get_clob_market_info(condition_id)
# info["fd"] = { "r": fee_rate, "e": exponent, "to": taker_only }
下一步
了解 Taker 费用如何为流动性提供者提供每日 USDC 返利。 开始在 Polymarket 上下单。 > ## Documentation Index > Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt > Use this file to discover all available pages before exploring further.
免 Gas 交易
无需支付 gas 费即可执行链上操作
Polymarket 的 Relayer Client 为你的用户提供免 gas 交易功能。用户无需持有 POL 来支付 gas 费,Polymarket 的基础设施会支付所有交易费用。这创造了一种无缝体验,用户只需要 pUSD 就能交易。
工作原理
relayer 充当交易赞助者:
- 你的应用创建一笔交易
- 用户用私钥签名
- 你的应用将交易发送到 Polymarket 的 relayer
- relayer 将交易提交到链上并支付 gas 费
- 交易从用户钱包执行
覆盖范围
Polymarket 为通过 relayer 路由的所有操作支付 gas:
| 操作 | 说明 |
|---|---|
| Wallet deployment | 为新用户部署 Safe 或 Proxy 钱包 |
| Token approvals | 授权合约使用 pUSD 或结果代币 |
| CTF operations | 拆分、合并和兑换仓位 |
| Transfers | 在地址之间转移代币 |
身份验证
relayer 使用 Relayer API Keys 。你可以在 Polymarket 网站的 Settings > API Keys 创建。
**已经有 builder 签名密钥?** 你现有的基于 HMAC 的 builder API key 在 Relayer 上继续有效 --- 无需轮换或重新签发。CLOB V2 中只有订单签名迁移到原生的 `builderCode` 字段。详见[迁移到 CLOB V2](/v2-migration#builder-program)。
请求中需要包含以下 header:
| Header | 说明 |
|---|---|
RELAYER_API_KEY |
你的 Relayer API key |
RELAYER_API_KEY_ADDRESS |
拥有该 key 的地址 |
如果你想直接使用 Relayer API Key 而不使用 SDK,请参阅 [Relayer API Reference](/api-reference/relayer)。
前置要求
使用 relayer 之前,你需要:
| 要求 | 来源 |
|---|---|
| Relayer API Key | Settings > API Keys |
| 用户的私钥或签名器 | 你的钱包集成 |
| pUSD 余额 | 用于交易(不是用于 gas) |
安装
```bash npm theme={null} npm install @polymarket/builder-relayer-client ```
bash
pip install py-builder-relayer-client
客户端设置
使用你的 Relayer API Key 初始化 relayer 客户端:
```typescript TypeScript theme={null} import { createWalletClient, http, Hex } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { polygon } from "viem/chains"; import { RelayClient } from "@polymarket/builder-relayer-client";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const wallet = createWalletClient({
account,
chain: polygon,
transport: http(process.env.RPC_URL),
});
const client = new RelayClient({
host: "https://relayer-v2.polymarket.com/",
chain: 137,
signer: wallet,
relayerApiKey: process.env.RELAYER_API_KEY!,
relayerApiKeyAddress: process.env.RELAYER_API_KEY_ADDRESS!,
});
```python Python theme={null}
import os
from py_builder_relayer_client.client import RelayClient
client = RelayClient(
host="https://relayer-v2.polymarket.com",
chain=137,
signer=os.getenv("PRIVATE_KEY"),
relayer_api_key=os.environ["RELAYER_API_KEY"],
relayer_api_key_address=os.environ["RELAYER_API_KEY_ADDRESS"],
)
永远不要在客户端代码中暴露你的 Relayer API Key。使用环境变量或密钥管理器。
钱包类型
初始化客户端时选择钱包类型:
| 类型 | 部署方式 | 最适用于 |
|---|---|---|
| Safe | 在首次交易前调用 deploy() |
大多数 builder 集成 |
| Proxy | 首次交易时自动部署 | Magic Link 用户 |
```typescript Safe Wallet (TypeScript) theme={null} import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
const client = new RelayClient({
host: "https://relayer-v2.polymarket.com/",
chain: 137,
signer: wallet,
relayerApiKey: process.env.RELAYER_API_KEY!,
relayerApiKeyAddress: process.env.RELAYER_API_KEY_ADDRESS!,
txType: RelayerTxType.SAFE,
});
// Deploy before first transaction
const response = await client.deploy();
const result = await response.wait();
console.log("Safe Address:", result?.proxyAddress);
```python Safe Wallet (Python) theme={null}
from py_builder_relayer_client.client import RelayClient
# client initialized with relayer credentials (see Client Setup above)
# Deploy before first transaction
response = client.deploy()
result = response.wait()
print("Safe Address:", result.get("proxyAddress"))
typescript
import { RelayClient, RelayerTxType } from "@polymarket/builder-relayer-client";
const client = new RelayClient({
host: "https://relayer-v2.polymarket.com/",
chain: 137,
signer: wallet,
relayerApiKey: process.env.RELAYER_API_KEY!,
relayerApiKeyAddress: process.env.RELAYER_API_KEY_ADDRESS!,
txType: RelayerTxType.PROXY,
});
// No deploy needed - auto-deploys on first transaction
python
from py_builder_relayer_client.client import RelayClient
# client initialized with relayer credentials (see Client Setup above)
# No deploy needed - auto-deploys on first transaction
执行交易
使用 execute 方法通过 relayer 发送交易:
typescript
interface Transaction {
to: string; // Target contract address
data: string; // Encoded function call
value: string; // POL to send (usually "0")
}
const response = await client.execute(transactions, "Description");
const result = await response.wait();
代币授权
授权合约使用代币:
```typescript TypeScript theme={null} import { encodeFunctionData, maxUint256 } from "viem";
const pUSD = "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB";
const CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045";
const approveTx = {
to: pUSD,
data: encodeFunctionData({
abi: [
{
name: "approve",
type: "function",
inputs: [
{ name: "spender", type: "address" },
{ name: "amount", type: "uint256" },
],
outputs: [{ type: "bool" }],
},
],
functionName: "approve",
args: [CTF, maxUint256],
}),
value: "0",
};
const response = await client.execute([approveTx], "Approve pUSD for CTF");
await response.wait();
```python Python theme={null}
from web3 import Web3
pUSD = "0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB"
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
MAX_UINT256 = 2**256 - 1
approve_tx = {
"to": pUSD,
"data": Web3().eth.contract(
address=pUSD,
abi=[{
"name": "approve",
"type": "function",
"inputs": [
{"name": "spender", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"outputs": [{"type": "bool"}]
}]
).encode_abi(abi_element_identifier="approve", args=[CTF, MAX_UINT256]),
"value": "0"
}
response = client.execute([approve_tx], "Approve pUSD for CTF")
response.wait()
兑换仓位
市场判定后,将获胜代币兑换为 pUSD:
```typescript TypeScript theme={null} import { encodeFunctionData } from "viem";
const redeemTx = {
to: CTF_ADDRESS,
data: encodeFunctionData({
abi: [
{
name: "redeemPositions",
type: "function",
inputs: [
{ name: "collateralToken", type: "address" },
{ name: "parentCollectionId", type: "bytes32" },
{ name: "conditionId", type: "bytes32" },
{ name: "indexSets", type: "uint256[]" },
],
outputs: [],
},
],
functionName: "redeemPositions",
args: [collateralToken, parentCollectionId, conditionId, indexSets],
}),
value: "0",
};
const response = await client.execute([redeemTx], "Redeem positions");
await response.wait();
```python Python theme={null}
CTF = "0x4D97DCd97eC945f40cF65F87097ACe5EA0476045"
redeem_tx = {
"to": CTF,
"data": Web3().eth.contract(
address=CTF,
abi=[{
"name": "redeemPositions",
"type": "function",
"inputs": [
{"name": "collateralToken", "type": "address"},
{"name": "parentCollectionId", "type": "bytes32"},
{"name": "conditionId", "type": "bytes32"},
{"name": "indexSets", "type": "uint256[]"}
],
"outputs": []
}]
).encode_abi(
abi_element_identifier="redeemPositions",
args=[collateral_token, parent_collection_id, condition_id, index_sets]
),
"value": "0"
}
response = client.execute([redeem_tx], "Redeem positions")
response.wait()
批量交易
在单次调用中原子性地执行多个操作:
```typescript TypeScript theme={null} const approveTx = { to: pUSD, data: encodeFunctionData({ abi: erc20Abi, functionName: "approve", args: [CTF, maxUint256], }), value: "0", };
const transferTx = {
to: pUSD,
data: encodeFunctionData({
abi: erc20Abi,
functionName: "transfer",
args: [recipientAddress, parseUnits("50", 6)],
}),
value: "0",
};
// Both execute atomically
const response = await client.execute(
approveTx, transferTx\],
"Approve and transfer",
);
await response.wait();
```python Python theme={null}
approve_tx = {
"to": pUSD,
"data": contract.encode_abi(
abi_element_identifier="approve",
args=[CTF, MAX_UINT256]
),
"value": "0"
}
transfer_tx = {
"to": pUSD,
"data": contract.encode_abi(
abi_element_identifier="transfer",
args=[recipient_address, 50 * 10**6]
),
"value": "0"
}
# Both execute atomically
response = client.execute([approve_tx, transfer_tx], "Approve and transfer")
response.wait()
批量处理可以减少延迟,并确保所有交易要么全部成功,要么全部失败。
### 交易状态
通过这些状态跟踪交易进度:
| 状态 | 终态 | 说明 |
|-------------------|----|---------------|
| `STATE_NEW` | 否 | relayer 已收到交易 |
| `STATE_EXECUTED` | 否 | 已提交到链上 |
| `STATE_MINED` | 否 | 已打包进区块 |
| `STATE_CONFIRMED` | 是 | 成功确认 |
| `STATE_FAILED` | 是 | 永久失败 |
| `STATE_INVALID` | 是 | 被拒绝为无效 |
### 合约地址
所有 Polymarket 智能合约地址详见[合约](/resources/contracts)。
### 资源
* [Builder Relayer Client (TypeScript)](https://github.com/Polymarket/builder-relayer-client)
* [Builder Relayer Client (Python)](https://github.com/Polymarket/py-builder-relayer-client)
### 下一步
了解多结果事件的资本高效交易。 理解拆分、合并和兑换等代币操作。 \> ## Documentation Index \> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt \> Use this file to discover all available pages before exploring further.
## Negative Risk 市场
> 多结果事件的资金高效交易机制
**Negative Risk** 是一种针对"只有一个结果能获胜"的多结果事件的机制。它通过**转换**操作将同一事件内所有结果的持仓关联起来,从而实现资金的高效利用。
### 运作方式
在标准的多结果事件中,每个市场是独立的。如果你想看空某个结果,必须买入该结果的 No 代币------但这些 No 代币与其他结果没有任何关联。
Negative Risk 改变了这一点。在 neg risk 事件中:
* 任何市场的 **No 份额** 都可以转换为**其他所有市场的各 1 份 Yes 份额**
* 转换通过 Neg Risk Adapter 合约完成
#### 示例
假设有一个事件:"谁将赢得 2024 年美国总统大选?",包含三个结果:
| 结果 | 你的持仓 |
|--------|------|
| Trump | --- |
| Harris | --- |
| 其他 | 1 No |
通过 Negative Risk,那 1 份 "其他" 的 No 可以转换为:
| 结果 | 转换后 |
|--------|-------|
| Trump | 1 Yes |
| Harris | 1 Yes |
| 其他 | --- |
这种方式非常高效,因为看空某一个结果在经济上等价于看多所有其他结果。
### 识别 Neg Risk 市场
Gamma API 在事件和市场上提供了 `negRisk` 布尔字段:
```json
{
"id": "123",
"title": "Who will win the 2024 Presidential Election?",
"negRisk": true,
"markets": [...]
}
```
在 neg risk 市场下单时,必须在订单选项中指定:
```typescript
const response = await client.createAndPostOrder(
{
tokenID: "TOKEN_ID",
price: 0.5,
size: 100,
side: Side.BUY,
},
{
tickSize: "0.01",
negRisk: true, // Required for neg risk markets
},
);
```
### 合约地址
Neg risk 市场使用与标准市场不同的合约:
Neg Risk Adapter 和 Neg Risk CTF Exchange 的地址详见[合约](/resources/contracts)。
### 增强型 Negative Risk
标准 Negative Risk 要求在市场创建时就确定所有结果。但有时新的结果会在交易开始后出现(例如,新候选人加入竞选)。
**增强型 Negative Risk** 通过以下方式解决这个问题:
| 结果类型 | 说明 |
|----------|-------------------------------|
| **命名结果** | 已知的结果(例如 "Trump"、"Harris") |
| **占位结果** | 预留的名额,后续可以明确指定(例如 "Person A") |
| **显式其他** | 涵盖所有未被明确命名的结果 |
#### 占位结果的运作方式
1. 事件上线时包含命名结果 + 占位结果 + "其他"
2. 当新结果出现时,通过公告板明确某个占位结果的身份
3. 随着占位结果被指定,"其他"的定义范围逐渐缩小
#### 增强型 Neg Risk 的交易规则
只交易\*\*命名结果\*\*。占位结果在被命名之前或判定发生之前应忽略。Polymarket 界面不会显示未命名的结果。
* 如果判定时正确结果未被命名,市场判定为 "其他"
* "其他"结果的定义会随着占位结果的指定而变化------避免直接交易
#### 识别增强型 Neg Risk
当以下两个标志同时为 true 时,表示事件为增强型 neg risk:
```json
{
"enableNegRisk": true,
"negRiskAugmented": true
}
```
Gamma API 在事件和市场上提供了 \`negRisk\` 布尔字段,表示该事件是否使用 negative risk。对于增强型 neg risk 事件,还有一个 \`enableNegRisk\` 字段也为 \`true\`。下单时,SDK 选项始终为 \`negRisk: true\` / \`neg_risk: True\`,无论市场是标准还是增强型 neg risk。
### 技术细节
#### 转换机制
转换操作是原子性的,通过 Neg Risk Adapter 完成:
1. 你持有结果 A 的 1 个 No 代币
2. 调用 adapter 的转换函数
3. 你获得该事件中每个其他结果各 1 个 Yes 代币
### 相关资源
* [Neg Risk Adapter 源代码](https://github.com/Polymarket/neg-risk-ctf-adapter)
* [Gamma API 文档](/market-data/overview)
### 下一步
了解多市场事件的组织结构。 了解拆分、合并和兑换等代币操作。 \> ## Documentation Index \> Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt \> Use this file to discover all available pages before exploring further.
## 撮合引擎重启
> 重启计划、维护窗口及停机处理
Polymarket 撮合引擎会定期重启以进行维护和升级。本页介绍重启计划、如何检测和处理停机以及如何获取变更的提前通知。
*** ** * ** ***
### 重启计划
撮合引擎\*\*每周二 7:00 AM ET(美东时间)\*\*进行重启。在重启窗口期间,引擎暂时不可用------通常约 **90 秒**。
| | 详情 |
|------------|---------------------|
| **频率** | 每周 |
| **日期和时间** | 周二 7:00 AM ET |
| **典型持续时间** | 约 90 秒 |
| **发生情况** | 订单撮合暂停,API 返回 `425` |
可能会因关键更新或紧急修复而进行计划外重启。这些将尽可能提前通知。
*** ** * ** ***
### 公告
撮合引擎变更------计划重启、更新和维护窗口------会在发生**之前**在以下渠道公告:
加入 Polymarket Trading APIs 频道获取实时公告。 加入 Polymarket Discord 的 #trading-apis 频道。
公告通常包括**变更内容** 、**计划时间** 和**预计停机窗口**。目标是尽可能提前约 2 天通知。
*** ** * ** ***
### 处理 HTTP 425
在重启窗口期间,CLOB API 在所有订单相关端点上返回 **HTTP 425(Too Early)**。这告诉你的客户端撮合引擎正在重启,很快会恢复。
#### 建议的重试策略
当收到 HTTP \`425\` 响应时,撮合引擎正在重启。不要将其视为永久错误。 等待并使用指数退避重试。从 1-2 秒开始,每次重试增加间隔。 一旦收到成功响应,引擎已恢复在线。恢复正常的订单流程。
#### 代码示例
检查 CLOB API 响应的 HTTP 状态码,在收到 `425` 时重试:
\`\`\`typescript TypeScript theme={null} const CLOB_HOST = "https://clob.polymarket.com";
async function postWithRetry(path: string, body: any, headers: Record\